Compare commits
119 Commits
@0x/contra
...
@0x/asset-
Author | SHA1 | Date | |
---|---|---|---|
|
f0738fc122 | ||
|
42baf504b7 | ||
|
56038d122f | ||
|
c4446b6c0e | ||
|
eaed2958c3 | ||
|
a045a3afb8 | ||
|
1cc59ab1ab | ||
|
2c6a714b71 | ||
|
d8c97d6720 | ||
|
d6bc702550 | ||
|
2838cb9420 | ||
|
b10cfc50d3 | ||
|
2e6317b01e | ||
|
50e99e6eac | ||
|
8f2f4554eb | ||
|
67d9678a3a | ||
|
f70341fb48 | ||
|
14cd24ea47 | ||
|
78328056d7 | ||
|
0045a60b0f | ||
|
e4e71c76e1 | ||
|
ca8127545f | ||
|
7b709089ce | ||
|
190f7e45f2 | ||
|
0dcc3a6fc3 | ||
|
c2e8cae293 | ||
|
83da7caab4 | ||
|
fd69a0c273 | ||
|
9b131199ad | ||
|
f5c486050b | ||
|
1f41fe6a20 | ||
|
7f4080e0a2 | ||
|
db76da58d7 | ||
|
cf8fc0ff8e | ||
|
2d16f83e37 | ||
|
4057bdab91 | ||
|
1cd10f0ac9 | ||
|
68f87b2432 | ||
|
69bafc3bcd | ||
|
2c44b06b7b | ||
|
0233f00b4e | ||
|
fedb53187d | ||
|
6774d2f588 | ||
|
cf740b74f5 | ||
|
177c00463a | ||
|
49b0e32129 | ||
|
938fc94756 | ||
|
1561d91c2b | ||
|
9a28e51f51 | ||
|
f55eaa867b | ||
|
6b2856424a | ||
|
da757c4700 | ||
|
75e6654884 | ||
|
87308e7693 | ||
|
d5eef93a76 | ||
|
a7f23a982e | ||
|
9eadc5fc28 | ||
|
92ad1a612e | ||
|
09413c0e12 | ||
|
23788b41d5 | ||
|
ccf999a495 | ||
|
aa1016ee5f | ||
|
423ef57344 | ||
|
c18149e82f | ||
|
d14aebf724 | ||
|
ba719a9631 | ||
|
d36034d958 | ||
|
7750c57620 | ||
|
4d027e11d1 | ||
|
470e9a4697 | ||
|
7c51412e2f | ||
|
b3d1f3cd10 | ||
|
389bb77439 | ||
|
4327885a00 | ||
|
0aef0afbbb | ||
|
fa4c3a4f5f | ||
|
1d7c527c5c | ||
|
cbe3135e4b | ||
|
955ad49711 | ||
|
8d6f6e76e0 | ||
|
9337115650 | ||
|
fa45a44fe4 | ||
|
c9c7ac8559 | ||
|
c881723578 | ||
|
c9c30d3a76 | ||
|
73dfdb5b69 | ||
|
e638268f94 | ||
|
0bfd765481 | ||
|
1f12893735 | ||
|
dd3d9337c4 | ||
|
904214f4a8 | ||
|
64c090c4b4 | ||
|
e24474f152 | ||
|
29fa408256 | ||
|
1b94cc68af | ||
|
f5b4bb3035 | ||
|
afd880f28c | ||
|
cd14cdd168 | ||
|
c8ff53a75f | ||
|
6d08add20b | ||
|
29f9c725e3 | ||
|
a83453f07f | ||
|
ae365ce92c | ||
|
77a592e891 | ||
|
9a1df67d6b | ||
|
4b91411faf | ||
|
622a542d57 | ||
|
cba53a9a50 | ||
|
e186f27f63 | ||
|
4cd767ecb8 | ||
|
f6e85aedf1 | ||
|
b3ee294ba5 | ||
|
1c242def93 | ||
|
f0fe6f2f69 | ||
|
f86d555e49 | ||
|
b0f2c40463 | ||
|
87be6fbb8a | ||
|
9141a9d2c8 | ||
|
7f75de347e |
@@ -19,7 +19,6 @@ jobs:
|
||||
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
||||
- setup_remote_docker
|
||||
- run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
|
||||
- run: yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts
|
||||
- save_cache:
|
||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
@@ -110,6 +109,8 @@ jobs:
|
||||
docker:
|
||||
- image: node:16
|
||||
working_directory: ~/repo
|
||||
environment:
|
||||
RUST_ROUTER: 'true'
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
@@ -117,7 +118,6 @@ jobs:
|
||||
- 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:
|
||||
|
1
.github/autolabeler.yml
vendored
1
.github/autolabeler.yml
vendored
@@ -1,7 +1,6 @@
|
||||
python: ['python-packages']
|
||||
contracts: ['contracts']
|
||||
@0x/contract-addresses: ['packages/contract-addresses']
|
||||
@0x/migrations: ['packages/migrations']
|
||||
@0x/order-utils: ['packages/order-utils']
|
||||
@0x/contract-artifacts: ['packages/contract-artifacts']
|
||||
@0x/contract-wrappers: ['packages/contract-wrappers']
|
||||
|
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 16
|
||||
- uses: actions/setup-python@v2
|
||||
- name: 'configure git'
|
||||
run: |
|
||||
|
@@ -38,7 +38,6 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
||||
| [`@0x/protocol-utils`](/packages/protocol-utils) | [](https://www.npmjs.com/package/@0x/protocol-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
|
||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
||||
| [`@0x/migrations`](/packages/migrations) | [](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
|
||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
|
||||
|
||||
## Usage
|
||||
|
@@ -1,4 +1,49 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1655244958,
|
||||
"version": "3.3.32",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1654284040,
|
||||
"version": "3.3.31",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1652919697,
|
||||
"version": "3.3.30",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1650611093,
|
||||
"version": "3.3.29",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1648739346,
|
||||
"version": "3.3.28",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1646225739,
|
||||
"version": "3.3.27",
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.3.32 - _June 14, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.31 - _June 3, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.30 - _May 19, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.29 - _April 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.28 - _March 31, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.27 - _March 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.3.27",
|
||||
"version": "3.3.32",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,18 +51,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.7.2",
|
||||
"@0x/contracts-gen": "^2.0.43",
|
||||
"@0x/contracts-test-utils": "^5.4.18",
|
||||
"@0x/contracts-utils": "^4.8.8",
|
||||
"@0x/dev-utils": "^4.2.11",
|
||||
"@0x/sol-compiler": "^4.7.8",
|
||||
"@0x/abi-gen": "^5.8.0",
|
||||
"@0x/contracts-gen": "^2.0.46",
|
||||
"@0x/contracts-test-utils": "^5.4.23",
|
||||
"@0x/contracts-utils": "^4.8.13",
|
||||
"@0x/dev-utils": "^4.2.14",
|
||||
"@0x/sol-compiler": "^4.8.1",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.5.0",
|
||||
"@0x/web3-wrapper": "^7.6.2",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
"@0x/utils": "^6.5.3",
|
||||
"@0x/web3-wrapper": "^7.6.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "12.12.54",
|
||||
@@ -70,7 +70,7 @@
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereum-types": "^3.7.0",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
@@ -79,10 +79,10 @@
|
||||
"solhint": "^1.4.1",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "4.2.2"
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.5",
|
||||
"@0x/base-contract": "^6.5.0",
|
||||
"ethers": "~4.0.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,49 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1655244958,
|
||||
"version": "5.4.23",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1654284040,
|
||||
"version": "5.4.22",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1652919697,
|
||||
"version": "5.4.21",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1650611093,
|
||||
"version": "5.4.20",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1648739346,
|
||||
"version": "5.4.19",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1646225739,
|
||||
"version": "5.4.18",
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.4.23 - _June 14, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.22 - _June 3, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.21 - _May 19, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.20 - _April 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.19 - _March 31, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.18 - _March 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.4.18",
|
||||
"version": "5.4.23",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -34,28 +34,28 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/test-utils",
|
||||
"devDependencies": {
|
||||
"@0x/sol-compiler": "^4.7.8",
|
||||
"@0x/sol-compiler": "^4.8.1",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "4.2.2"
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.31",
|
||||
"@0x/base-contract": "^6.4.5",
|
||||
"@0x/contract-addresses": "^6.12.0",
|
||||
"@0x/dev-utils": "^4.2.11",
|
||||
"@0x/json-schemas": "^6.4.1",
|
||||
"@0x/assert": "^3.0.34",
|
||||
"@0x/base-contract": "^6.5.0",
|
||||
"@0x/contract-addresses": "^6.16.0",
|
||||
"@0x/dev-utils": "^4.2.14",
|
||||
"@0x/json-schemas": "^6.4.4",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-coverage": "^4.0.42",
|
||||
"@0x/sol-profiler": "^4.1.32",
|
||||
"@0x/sol-trace": "^3.0.42",
|
||||
"@0x/subproviders": "^6.6.2",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.5.0",
|
||||
"@0x/web3-wrapper": "^7.6.2",
|
||||
"@0x/sol-coverage": "^4.0.45",
|
||||
"@0x/sol-profiler": "^4.1.35",
|
||||
"@0x/sol-trace": "^3.0.45",
|
||||
"@0x/subproviders": "^6.6.5",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
"@0x/utils": "^6.5.3",
|
||||
"@0x/web3-wrapper": "^7.6.5",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/js-combinatorics": "^0.5.29",
|
||||
"@types/lodash": "4.14.104",
|
||||
@@ -67,7 +67,7 @@
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"decimal.js": "^10.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereum-types": "^3.7.0",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"ethers": "~4.0.4",
|
||||
"js-combinatorics": "^0.5.3",
|
||||
|
@@ -1,4 +1,49 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1655244958,
|
||||
"version": "1.4.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1654284040,
|
||||
"version": "1.4.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1652919697,
|
||||
"version": "1.4.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1650611093,
|
||||
"version": "1.4.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1648739346,
|
||||
"version": "1.4.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1646225739,
|
||||
"version": "1.4.10",
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.4.15 - _June 14, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.14 - _June 3, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.13 - _May 19, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.12 - _April 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.11 - _March 31, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.10 - _March 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-treasury",
|
||||
"version": "1.4.10",
|
||||
"version": "1.4.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -46,14 +46,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.7.2",
|
||||
"@0x/contract-addresses": "^6.12.0",
|
||||
"@0x/abi-gen": "^5.8.0",
|
||||
"@0x/contract-addresses": "^6.16.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.19",
|
||||
"@0x/contracts-erc20": "^3.3.27",
|
||||
"@0x/contracts-gen": "^2.0.43",
|
||||
"@0x/contracts-erc20": "^3.3.32",
|
||||
"@0x/contracts-gen": "^2.0.46",
|
||||
"@0x/contracts-staking": "^2.0.45",
|
||||
"@0x/contracts-test-utils": "^5.4.18",
|
||||
"@0x/sol-compiler": "^4.7.8",
|
||||
"@0x/contracts-test-utils": "^5.4.23",
|
||||
"@0x/sol-compiler": "^4.8.1",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@types/isomorphic-fetch": "^0.0.35",
|
||||
@@ -69,17 +69,17 @@
|
||||
"solhint": "^1.4.1",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "4.2.2"
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.5",
|
||||
"@0x/protocol-utils": "^1.11.1",
|
||||
"@0x/subproviders": "^6.6.2",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.5.0",
|
||||
"@0x/web3-wrapper": "^7.6.2",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"@0x/base-contract": "^6.5.0",
|
||||
"@0x/protocol-utils": "^11.15.0",
|
||||
"@0x/subproviders": "^6.6.5",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
"@0x/utils": "^6.5.3",
|
||||
"@0x/web3-wrapper": "^7.6.5",
|
||||
"ethereum-types": "^3.7.0",
|
||||
"ethereumjs-util": "^7.0.10"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,49 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1655244958,
|
||||
"version": "4.8.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1654284040,
|
||||
"version": "4.8.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1652919697,
|
||||
"version": "4.8.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1650611093,
|
||||
"version": "4.8.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1648739346,
|
||||
"version": "4.8.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1646225739,
|
||||
"version": "4.8.8",
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.8.13 - _June 14, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.12 - _June 3, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.11 - _May 19, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.10 - _April 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.9 - _March 31, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.8 - _March 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.8.8",
|
||||
"version": "4.8.13",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,15 +50,15 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/utils",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.7.2",
|
||||
"@0x/contracts-gen": "^2.0.43",
|
||||
"@0x/contracts-test-utils": "^5.4.18",
|
||||
"@0x/dev-utils": "^4.2.11",
|
||||
"@0x/abi-gen": "^5.8.0",
|
||||
"@0x/contracts-gen": "^2.0.46",
|
||||
"@0x/contracts-test-utils": "^5.4.23",
|
||||
"@0x/dev-utils": "^4.2.14",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-compiler": "^4.7.8",
|
||||
"@0x/sol-compiler": "^4.8.1",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/web3-wrapper": "^7.6.2",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/web3-wrapper": "^7.6.5",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -76,14 +76,14 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "4.2.2"
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.5",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.5.0",
|
||||
"@0x/base-contract": "^6.5.0",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
"@0x/utils": "^6.5.3",
|
||||
"bn.js": "^4.11.8",
|
||||
"ethereum-types": "^3.6.0"
|
||||
"ethereum-types": "^3.7.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,61 @@
|
||||
[
|
||||
{
|
||||
"version": "0.35.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Adds support for Velodrome OptimismBridgeAdapter",
|
||||
"pr": 494
|
||||
}
|
||||
],
|
||||
"timestamp": 1655244958
|
||||
},
|
||||
{
|
||||
"version": "0.34.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Splits BridgeAdapter up by chain",
|
||||
"pr": 487
|
||||
},
|
||||
{
|
||||
"note": "Add stETH wrap/unwrap support",
|
||||
"pr": 476
|
||||
},
|
||||
{
|
||||
"note": "Adds support for BancorV3 to EthereumBridgeAdapter",
|
||||
"pr": 492
|
||||
}
|
||||
],
|
||||
"timestamp": 1654284040
|
||||
},
|
||||
{
|
||||
"version": "0.33.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add support for GMX and Platypus to bridge adapter",
|
||||
"pr": 478
|
||||
}
|
||||
],
|
||||
"timestamp": 1652919697
|
||||
},
|
||||
{
|
||||
"version": "0.32.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add support for `BalancerV2Batch` fills in FQT",
|
||||
"pr": 462
|
||||
}
|
||||
],
|
||||
"timestamp": 1650611093
|
||||
},
|
||||
{
|
||||
"timestamp": 1648739346,
|
||||
"version": "0.31.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1646225739,
|
||||
"version": "0.31.1",
|
||||
|
@@ -5,6 +5,28 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.35.0 - _June 14, 2022_
|
||||
|
||||
* Adds support for Velodrome OptimismBridgeAdapter (#494)
|
||||
|
||||
## v0.34.0 - _June 3, 2022_
|
||||
|
||||
* Splits BridgeAdapter up by chain (#487)
|
||||
* Add stETH wrap/unwrap support (#476)
|
||||
* Adds support for BancorV3 to EthereumBridgeAdapter (#492)
|
||||
|
||||
## v0.33.0 - _May 19, 2022_
|
||||
|
||||
* Add support for GMX and Platypus to bridge adapter (#478)
|
||||
|
||||
## v0.32.0 - _April 22, 2022_
|
||||
|
||||
* Add support for `BalancerV2Batch` fills in FQT (#462)
|
||||
|
||||
## v0.31.2 - _March 31, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.31.1 - _March 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./IBridgeAdapter.sol";
|
||||
|
||||
abstract contract AbstractBridgeAdapter is IBridgeAdapter {
|
||||
|
||||
constructor(
|
||||
uint256 expectedChainId,
|
||||
string memory expectedChainName
|
||||
)
|
||||
public
|
||||
{
|
||||
uint256 chainId;
|
||||
assembly { chainId := chainid() }
|
||||
// Allow testing on Ganache
|
||||
if (chainId != expectedChainId && chainId != 1337) {
|
||||
revert(string(abi.encodePacked(expectedChainName, "BridgeAdapter.constructor: wrong chain ID")));
|
||||
}
|
||||
}
|
||||
|
||||
function isSupportedSource(bytes32 source)
|
||||
external
|
||||
override
|
||||
returns (bool isSupported)
|
||||
{
|
||||
BridgeOrder memory placeholderOrder;
|
||||
placeholderOrder.source = source;
|
||||
IERC20TokenV06 placeholderToken = IERC20TokenV06(address(0));
|
||||
|
||||
(, isSupported) = _trade(
|
||||
placeholderOrder,
|
||||
placeholderToken,
|
||||
placeholderToken,
|
||||
0,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
function trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount
|
||||
)
|
||||
public
|
||||
override
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(boughtAmount, ) = _trade(
|
||||
order,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
internal
|
||||
virtual
|
||||
returns (uint256 boughtAmount, bool supportedSource);
|
||||
}
|
@@ -0,0 +1,141 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./AbstractBridgeAdapter.sol";
|
||||
import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
import "./mixins/MixinGMX.sol";
|
||||
import "./mixins/MixinKyberDmm.sol";
|
||||
import "./mixins/MixinAaveV2.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinPlatypus.sol";
|
||||
import "./mixins/MixinUniswapV2.sol";
|
||||
import "./mixins/MixinZeroExBridge.sol";
|
||||
|
||||
contract AvalancheBridgeAdapter is
|
||||
AbstractBridgeAdapter(43114, "Avalanche"),
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
MixinGMX,
|
||||
MixinKyberDmm,
|
||||
MixinAaveV2,
|
||||
MixinNerve,
|
||||
MixinPlatypus,
|
||||
MixinUniswapV2,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinCurve(weth)
|
||||
{}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
internal
|
||||
override
|
||||
returns (uint256 boughtAmount, bool supportedSource)
|
||||
{
|
||||
uint128 protocolId = uint128(uint256(order.source) >> 128);
|
||||
if (protocolId == BridgeProtocols.CURVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurve(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CURVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.NERVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeNerve(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.KYBERDMM) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeKyberDmm(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.AAVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeAaveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.GMX) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeGMX(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.PLATYPUS) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradePlatypus(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNKNOWN) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
emit BridgeFill(
|
||||
order.source,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
boughtAmount
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./AbstractBridgeAdapter.sol";
|
||||
import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyberDmm.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinUniswapV2.sol";
|
||||
import "./mixins/MixinZeroExBridge.sol";
|
||||
|
||||
contract BSCBridgeAdapter is
|
||||
AbstractBridgeAdapter(56, "BSC"),
|
||||
MixinCurve,
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyberDmm,
|
||||
MixinMooniswap,
|
||||
MixinNerve,
|
||||
MixinUniswapV2,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinCurve(weth)
|
||||
MixinMooniswap(weth)
|
||||
{}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
internal
|
||||
override
|
||||
returns (uint256 boughtAmount, bool supportedSource)
|
||||
{
|
||||
uint128 protocolId = uint128(uint256(order.source) >> 128);
|
||||
if (protocolId == BridgeProtocols.CURVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurve(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.MOONISWAP) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeMooniswap(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.DODO) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeDodo(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.DODOV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeDodoV2(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.NERVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeNerve(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.KYBERDMM) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeKyberDmm(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNKNOWN) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
emit BridgeFill(
|
||||
order.source,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
boughtAmount
|
||||
);
|
||||
}
|
||||
}
|
@@ -27,29 +27,34 @@ library BridgeProtocols {
|
||||
// A incrementally increasing, append-only list of protocol IDs.
|
||||
// We don't use an enum so solidity doesn't throw when we pass in a
|
||||
// new protocol ID that hasn't been rolled up yet.
|
||||
uint128 internal constant UNKNOWN = 0;
|
||||
uint128 internal constant CURVE = 1;
|
||||
uint128 internal constant UNISWAPV2 = 2;
|
||||
uint128 internal constant UNISWAP = 3;
|
||||
uint128 internal constant BALANCER = 4;
|
||||
uint128 internal constant KYBER = 5;
|
||||
uint128 internal constant MOONISWAP = 6;
|
||||
uint128 internal constant MSTABLE = 7;
|
||||
uint128 internal constant OASIS = 8;
|
||||
uint128 internal constant SHELL = 9;
|
||||
uint128 internal constant DODO = 10;
|
||||
uint128 internal constant DODOV2 = 11;
|
||||
uint128 internal constant CRYPTOCOM = 12;
|
||||
uint128 internal constant BANCOR = 13;
|
||||
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;
|
||||
uint128 internal constant KYBERDMM = 19;
|
||||
uint128 internal constant CURVEV2 = 20;
|
||||
uint128 internal constant LIDO = 21;
|
||||
uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface
|
||||
uint128 internal constant AAVEV2 = 23;
|
||||
uint128 internal constant COMPOUND = 24;
|
||||
uint128 internal constant UNKNOWN = 0;
|
||||
uint128 internal constant CURVE = 1;
|
||||
uint128 internal constant UNISWAPV2 = 2;
|
||||
uint128 internal constant UNISWAP = 3;
|
||||
uint128 internal constant BALANCER = 4;
|
||||
uint128 internal constant KYBER = 5; // Not used: deprecated.
|
||||
uint128 internal constant MOONISWAP = 6;
|
||||
uint128 internal constant MSTABLE = 7;
|
||||
uint128 internal constant OASIS = 8; // Not used: deprecated.
|
||||
uint128 internal constant SHELL = 9;
|
||||
uint128 internal constant DODO = 10;
|
||||
uint128 internal constant DODOV2 = 11;
|
||||
uint128 internal constant CRYPTOCOM = 12;
|
||||
uint128 internal constant BANCOR = 13;
|
||||
uint128 internal constant COFIX = 14; // Not used: deprecated.
|
||||
uint128 internal constant NERVE = 15;
|
||||
uint128 internal constant MAKERPSM = 16;
|
||||
uint128 internal constant BALANCERV2 = 17;
|
||||
uint128 internal constant UNISWAPV3 = 18;
|
||||
uint128 internal constant KYBERDMM = 19;
|
||||
uint128 internal constant CURVEV2 = 20;
|
||||
uint128 internal constant LIDO = 21;
|
||||
uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface
|
||||
uint128 internal constant AAVEV2 = 23;
|
||||
uint128 internal constant COMPOUND = 24;
|
||||
uint128 internal constant BALANCERV2BATCH = 25;
|
||||
uint128 internal constant GMX = 26;
|
||||
uint128 internal constant PLATYPUS = 27;
|
||||
uint128 internal constant BANCORV3 = 28;
|
||||
uint128 internal constant VELODROME = 29;
|
||||
}
|
||||
|
@@ -0,0 +1,84 @@
|
||||
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./AbstractBridgeAdapter.sol";
|
||||
import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinUniswapV2.sol";
|
||||
import "./mixins/MixinZeroExBridge.sol";
|
||||
|
||||
contract CeloBridgeAdapter is
|
||||
AbstractBridgeAdapter(42220, "Celo"),
|
||||
MixinNerve,
|
||||
MixinUniswapV2,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(address _weth)
|
||||
public
|
||||
{}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
internal
|
||||
override
|
||||
returns (uint256 boughtAmount, bool supportedSource)
|
||||
{
|
||||
uint128 protocolId = uint128(uint256(order.source) >> 128);
|
||||
if (protocolId == BridgeProtocols.UNISWAPV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.NERVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeNerve(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNKNOWN) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
emit BridgeFill(
|
||||
order.source,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
boughtAmount
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2022 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,54 +20,52 @@
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./IBridgeAdapter.sol";
|
||||
import "./AbstractBridgeAdapter.sol";
|
||||
import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinAaveV2.sol";
|
||||
import "./mixins/MixinBalancer.sol";
|
||||
import "./mixins/MixinBalancerV2.sol";
|
||||
import "./mixins/MixinBalancerV2Batch.sol";
|
||||
import "./mixins/MixinBancor.sol";
|
||||
import "./mixins/MixinCoFiX.sol";
|
||||
import "./mixins/MixinBancorV3.sol";
|
||||
import "./mixins/MixinCompound.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
import "./mixins/MixinCryptoCom.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyber.sol";
|
||||
import "./mixins/MixinKyberDmm.sol";
|
||||
import "./mixins/MixinLido.sol";
|
||||
import "./mixins/MixinMakerPSM.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
import "./mixins/MixinMStable.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
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,
|
||||
contract EthereumBridgeAdapter is
|
||||
AbstractBridgeAdapter(1, "Ethereum"),
|
||||
MixinAaveV2,
|
||||
MixinBalancer,
|
||||
MixinBalancerV2,
|
||||
MixinBalancerV2Batch,
|
||||
MixinBancor,
|
||||
MixinCoFiX,
|
||||
MixinBancorV3,
|
||||
MixinCompound,
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
MixinCryptoCom,
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyber,
|
||||
MixinKyberDmm,
|
||||
MixinLido,
|
||||
MixinMakerPSM,
|
||||
MixinMooniswap,
|
||||
MixinMStable,
|
||||
MixinNerve,
|
||||
MixinOasis,
|
||||
MixinShell,
|
||||
MixinUniswap,
|
||||
MixinUniswapV2,
|
||||
@@ -76,43 +74,29 @@ contract BridgeAdapter is
|
||||
{
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinAaveV2()
|
||||
MixinBalancer()
|
||||
MixinBalancerV2()
|
||||
MixinBancor(weth)
|
||||
MixinCoFiX()
|
||||
MixinBancorV3(weth)
|
||||
MixinCompound(weth)
|
||||
MixinCurve(weth)
|
||||
MixinCurveV2()
|
||||
MixinCryptoCom()
|
||||
MixinDodo()
|
||||
MixinDodoV2()
|
||||
MixinKyber(weth)
|
||||
MixinLido(weth)
|
||||
MixinMakerPSM()
|
||||
MixinMooniswap(weth)
|
||||
MixinMStable()
|
||||
MixinNerve()
|
||||
MixinOasis()
|
||||
MixinShell()
|
||||
MixinUniswap(weth)
|
||||
MixinUniswapV2()
|
||||
MixinUniswapV3()
|
||||
MixinZeroExBridge()
|
||||
{}
|
||||
|
||||
function trade(
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
public
|
||||
internal
|
||||
override
|
||||
returns (uint256 boughtAmount)
|
||||
returns (uint256 boughtAmount, bool supportedSource)
|
||||
{
|
||||
uint128 protocolId = uint128(uint256(order.source) >> 128);
|
||||
if (protocolId == BridgeProtocols.CURVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurve(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -120,6 +104,7 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CURVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -127,18 +112,21 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV3) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV3(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAP) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswap(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -146,6 +134,7 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.BALANCER) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBalancer(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -153,20 +142,21 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.BALANCERV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBalancerV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.KYBER) {
|
||||
boughtAmount = _tradeKyber(
|
||||
sellToken,
|
||||
buyToken,
|
||||
} else if (protocolId == BridgeProtocols.BALANCERV2BATCH) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBalancerV2Batch(
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.MAKERPSM) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeMakerPsm(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -174,6 +164,7 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.MOONISWAP) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeMooniswap(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -181,20 +172,15 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.MSTABLE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeMStable(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.OASIS) {
|
||||
boughtAmount = _tradeOasis(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.SHELL) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeShell(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -202,49 +188,49 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.DODO) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeDodo(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.DODOV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeDodoV2(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CRYPTOCOM) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCryptoCom(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.BANCOR) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBancor(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.COFIX) {
|
||||
boughtAmount = _tradeCoFiX(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.NERVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeNerve(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.KYBERDMM) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeKyberDmm(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.LIDO) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeLido(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -252,6 +238,7 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.AAVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeAaveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
@@ -259,13 +246,22 @@ contract BridgeAdapter is
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.COMPOUND) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCompound(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else {
|
||||
} else if (protocolId == BridgeProtocols.BANCORV3) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBancorV3(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNKNOWN) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
buyToken,
|
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./AbstractBridgeAdapter.sol";
|
||||
import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinAaveV2.sol";
|
||||
import "./mixins/MixinBalancerV2.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinUniswapV2.sol";
|
||||
import "./mixins/MixinZeroExBridge.sol";
|
||||
|
||||
contract FantomBridgeAdapter is
|
||||
AbstractBridgeAdapter(250, "Fantom"),
|
||||
MixinAaveV2,
|
||||
MixinBalancerV2,
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
MixinNerve,
|
||||
MixinUniswapV2,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinCurve(weth)
|
||||
{}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
internal
|
||||
override
|
||||
returns (uint256 boughtAmount, bool supportedSource)
|
||||
{
|
||||
uint128 protocolId = uint128(uint256(order.source) >> 128);
|
||||
if (protocolId == BridgeProtocols.CURVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurve(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CURVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.BALANCERV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBalancerV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.NERVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeNerve(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.AAVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeAaveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNKNOWN) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
emit BridgeFill(
|
||||
order.source,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
boughtAmount
|
||||
);
|
||||
}
|
||||
}
|
@@ -50,6 +50,10 @@ interface IBridgeAdapter {
|
||||
uint256 outputTokenAmount
|
||||
);
|
||||
|
||||
function isSupportedSource(bytes32 source)
|
||||
external
|
||||
returns (bool isSupported);
|
||||
|
||||
function trade(
|
||||
BridgeOrder calldata order,
|
||||
IERC20TokenV06 sellToken,
|
||||
|
@@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./AbstractBridgeAdapter.sol";
|
||||
import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinUniswapV3.sol";
|
||||
import "./mixins/MixinVelodrome.sol";
|
||||
import "./mixins/MixinZeroExBridge.sol";
|
||||
|
||||
contract OptimismBridgeAdapter is
|
||||
AbstractBridgeAdapter(10, "Optimism"),
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
MixinNerve,
|
||||
MixinUniswapV3,
|
||||
MixinVelodrome,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinCurve(weth)
|
||||
{}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
internal
|
||||
override
|
||||
returns (uint256 boughtAmount, bool supportedSource)
|
||||
{
|
||||
uint128 protocolId = uint128(uint256(order.source) >> 128);
|
||||
if (protocolId == BridgeProtocols.CURVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurve(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CURVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV3) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV3(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.NERVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeNerve(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.VELODROME) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeVelodrome(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNKNOWN) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
emit BridgeFill(
|
||||
order.source,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
boughtAmount
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./AbstractBridgeAdapter.sol";
|
||||
import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinAaveV2.sol";
|
||||
import "./mixins/MixinBalancerV2.sol";
|
||||
import "./mixins/MixinBalancerV2Batch.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyberDmm.sol";
|
||||
import "./mixins/MixinMStable.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinUniswapV2.sol";
|
||||
import "./mixins/MixinUniswapV3.sol";
|
||||
import "./mixins/MixinZeroExBridge.sol";
|
||||
|
||||
contract PolygonBridgeAdapter is
|
||||
AbstractBridgeAdapter(137, "Polygon"),
|
||||
MixinAaveV2,
|
||||
MixinBalancerV2,
|
||||
MixinBalancerV2Batch,
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyberDmm,
|
||||
MixinMStable,
|
||||
MixinNerve,
|
||||
MixinUniswapV2,
|
||||
MixinUniswapV3,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinCurve(weth)
|
||||
{}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bool dryRun
|
||||
)
|
||||
internal
|
||||
override
|
||||
returns (uint256 boughtAmount, bool supportedSource)
|
||||
{
|
||||
uint128 protocolId = uint128(uint256(order.source) >> 128);
|
||||
if (protocolId == BridgeProtocols.CURVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurve(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CURVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeCurveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV3) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV3(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.BALANCERV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBalancerV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.BALANCERV2BATCH) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeBalancerV2Batch(
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.MSTABLE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeMStable(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.DODO) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeDodo(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.DODOV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeDodoV2(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.NERVE) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeNerve(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.KYBERDMM) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeKyberDmm(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.AAVEV2) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeAaveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNKNOWN) {
|
||||
if (dryRun) { return (0, true); }
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
emit BridgeFill(
|
||||
order.source,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
boughtAmount
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
// 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 IBalancerV2BatchSwapVault {
|
||||
|
||||
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 batchSwap(
|
||||
SwapKind kind,
|
||||
BatchSwapStep[] calldata swaps,
|
||||
IERC20TokenV06[] calldata assets,
|
||||
FundManagement calldata funds,
|
||||
int256[] calldata limits,
|
||||
uint256 deadline
|
||||
) external returns (int256[] memory amounts);
|
||||
}
|
||||
|
||||
contract MixinBalancerV2Batch {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
struct BalancerV2BatchBridgeData {
|
||||
IBalancerV2BatchSwapVault vault;
|
||||
IBalancerV2BatchSwapVault.BatchSwapStep[] swapSteps;
|
||||
IERC20TokenV06[] assets;
|
||||
}
|
||||
|
||||
function _tradeBalancerV2Batch(
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(
|
||||
IBalancerV2BatchSwapVault vault,
|
||||
IBalancerV2BatchSwapVault.BatchSwapStep[] memory swapSteps,
|
||||
address[] memory assets_
|
||||
) = abi.decode(bridgeData, (IBalancerV2BatchSwapVault, IBalancerV2BatchSwapVault.BatchSwapStep[], address[]));
|
||||
IERC20TokenV06[] memory assets;
|
||||
assembly { assets := assets_ }
|
||||
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
assets[0].approveIfBelow(address(vault), sellAmount);
|
||||
|
||||
swapSteps[0].amount = sellAmount;
|
||||
int256[] memory limits = new int256[](assets.length);
|
||||
for (uint256 i = 0; i < limits.length; ++i) {
|
||||
limits[i] = type(int256).max;
|
||||
}
|
||||
|
||||
int256[] memory amounts = vault.batchSwap(
|
||||
IBalancerV2BatchSwapVault.SwapKind.GIVEN_IN,
|
||||
swapSteps,
|
||||
assets,
|
||||
IBalancerV2BatchSwapVault.FundManagement({
|
||||
sender: address(this),
|
||||
fromInternalBalance: false,
|
||||
recipient: payable(address(this)),
|
||||
toInternalBalance: false
|
||||
}),
|
||||
limits,
|
||||
block.timestamp + 1
|
||||
);
|
||||
require(amounts[amounts.length - 1] <= 0, 'Unexpected BalancerV2Batch output');
|
||||
return uint256(amounts[amounts.length - 1] * -1);
|
||||
}
|
||||
}
|
@@ -0,0 +1,128 @@
|
||||
// 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";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
|
||||
|
||||
/*
|
||||
BancorV3
|
||||
*/
|
||||
interface IBancorV3 {
|
||||
/**
|
||||
* @dev performs a trade by providing the source amount and returns the target amount and the associated fee
|
||||
*
|
||||
* requirements:
|
||||
*
|
||||
* - the caller must be the network contract
|
||||
*/
|
||||
function tradeBySourceAmount(
|
||||
address sourceToken,
|
||||
address targetToken,
|
||||
uint256 sourceAmount,
|
||||
uint256 minReturnAmount,
|
||||
uint256 deadline,
|
||||
address beneficiary
|
||||
) external payable returns (uint256 amount);
|
||||
}
|
||||
|
||||
contract MixinBancorV3 {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
IERC20TokenV06 constant public BANCORV3_ETH_ADDRESS =
|
||||
IERC20TokenV06(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
{
|
||||
WETH = weth;
|
||||
}
|
||||
|
||||
function _tradeBancorV3(
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 amountOut)
|
||||
|
||||
{
|
||||
IBancorV3 router;
|
||||
IERC20TokenV06[] memory path;
|
||||
address[] memory _path;
|
||||
uint256 payableAmount = 0;
|
||||
|
||||
{
|
||||
(router, _path) = abi.decode(bridgeData, (IBancorV3, address[]));
|
||||
// To get around `abi.decode()` not supporting interface array types.
|
||||
assembly { path := _path }
|
||||
}
|
||||
|
||||
require(path.length >= 2, "MixinBancorV3/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(
|
||||
path[path.length - 1] == buyToken,
|
||||
"MixinBancorV3/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
|
||||
);
|
||||
|
||||
//swap WETH->ETH as Bancor only deals in ETH
|
||||
if(_path[0] == address(WETH)) {
|
||||
//withdraw the sell amount of WETH for ETH
|
||||
WETH.withdraw(sellAmount);
|
||||
payableAmount = sellAmount;
|
||||
// set _path[0] to the ETH address if WETH is our buy token
|
||||
_path[0] = address(BANCORV3_ETH_ADDRESS);
|
||||
} else {
|
||||
// Grant the BancorV3 router an allowance to sell the first token.
|
||||
path[0].approveIfBelow(address(router), sellAmount);
|
||||
}
|
||||
|
||||
// if we are buying WETH we need to swap to ETH and deposit into WETH after the swap
|
||||
if(_path[1] == address(WETH)){
|
||||
_path[1] = address(BANCORV3_ETH_ADDRESS);
|
||||
}
|
||||
|
||||
|
||||
uint256 amountOut = router.tradeBySourceAmount{value: payableAmount}(
|
||||
_path[0],
|
||||
_path[1],
|
||||
// Sell all tokens we hold.
|
||||
sellAmount,
|
||||
// Minimum buy amount.
|
||||
1,
|
||||
//deadline
|
||||
block.timestamp + 1,
|
||||
// address of the mixin
|
||||
address(this)
|
||||
);
|
||||
|
||||
// if we want to return WETH deposit the ETH amount we sold
|
||||
if(buyToken == WETH){
|
||||
WETH.deposit{value: amountOut}();
|
||||
}
|
||||
|
||||
return amountOut;
|
||||
}
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
// 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";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
|
||||
|
||||
interface ICoFiXRouter {
|
||||
// msg.value = fee
|
||||
function swapExactTokensForETH(
|
||||
address token,
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address to,
|
||||
address rewardTo,
|
||||
uint deadline
|
||||
) external payable returns (uint _amountIn, uint _amountOut);
|
||||
|
||||
// msg.value = amountIn + fee
|
||||
function swapExactETHForTokens(
|
||||
address token,
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address to,
|
||||
address rewardTo,
|
||||
uint deadline
|
||||
) external payable returns (uint _amountIn, uint _amountOut);
|
||||
}
|
||||
|
||||
interface ICoFiXPair {
|
||||
|
||||
function swapWithExact(address outToken, address to)
|
||||
external
|
||||
payable
|
||||
returns (
|
||||
uint amountIn,
|
||||
uint amountOut,
|
||||
uint oracleFeeChange,
|
||||
uint256[4] memory tradeInfo
|
||||
);
|
||||
}
|
||||
|
||||
contract MixinCoFiX {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeCoFiX(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(uint256 fee, ICoFiXPair pool) = abi.decode(bridgeData, (uint256, ICoFiXPair));
|
||||
// Transfer tokens into the pool
|
||||
LibERC20TokenV06.compatTransfer(
|
||||
sellToken,
|
||||
address(pool),
|
||||
sellAmount
|
||||
);
|
||||
// Call the swap exact with the tokens now in the pool
|
||||
// pay the NEST Oracle fee with ETH
|
||||
(/* In */, boughtAmount, , ) = pool.swapWithExact{value: fee}(
|
||||
address(buyToken),
|
||||
address(this)
|
||||
);
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
// 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";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
import "../IBridgeAdapter.sol";
|
||||
|
||||
/*
|
||||
UniswapV2
|
||||
*/
|
||||
interface IGmxRouter {
|
||||
|
||||
// /// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
|
||||
// /// The first element of path is the input token, the last is the output token, and any intermediate elements represent
|
||||
// /// intermediate pairs to trade through (if, for example, a direct pair does not exist).
|
||||
// /// @param _path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity.
|
||||
// /// @param _amountIn The amount of input tokens to send.
|
||||
// /// @param _minOut The minimum amount of output tokens that must be received for the transaction not to revert.
|
||||
// /// @param _reciever Recipient of the output tokens.
|
||||
function swap(
|
||||
address[] calldata _path, uint256 _amountIn, uint256 _minOut, address _receiver
|
||||
) external;
|
||||
}
|
||||
|
||||
contract MixinGMX {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
function _tradeGMX(
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
public
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
address _router;
|
||||
address reader;
|
||||
address vault;
|
||||
address[] memory _path;
|
||||
IGmxRouter router;
|
||||
IERC20TokenV06[] memory path;
|
||||
|
||||
{
|
||||
//decode the bridge data
|
||||
(_router, reader, vault, _path) = abi.decode(bridgeData, (address, address, address, address[]));
|
||||
// To get around `abi.decode()` not supporting interface array types.
|
||||
assembly { path := _path }
|
||||
}
|
||||
|
||||
require(path.length >= 2, "MixinGMX/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(
|
||||
path[path.length - 1] == buyToken,
|
||||
"MixinGMX/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
|
||||
);
|
||||
|
||||
//connect to the GMX router
|
||||
router = IGmxRouter(_router);
|
||||
|
||||
// Grant the GMX router an allowance to sell the first token.
|
||||
path[0].approveIfBelow(address(router), sellAmount);
|
||||
|
||||
//track the balance to know how much we bought
|
||||
uint256 beforeBalance = buyToken.balanceOf(address(this));
|
||||
router.swap(
|
||||
// Convert to `buyToken` along this path.
|
||||
_path,
|
||||
// Sell all tokens we hold.
|
||||
sellAmount,
|
||||
// Minimum buy amount.
|
||||
0,
|
||||
// Recipient is `this`.
|
||||
address(this)
|
||||
);
|
||||
|
||||
//calculate the difference in balance from preswap->postswap to find how many tokens out
|
||||
boughtAmount = buyToken.balanceOf(address(this)).safeSub(beforeBalance);
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -1,124 +0,0 @@
|
||||
// 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";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "../IBridgeAdapter.sol";
|
||||
|
||||
interface IKyberNetworkProxy {
|
||||
|
||||
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens
|
||||
/// using a hint for the reserve.
|
||||
/// @param sellToken Token to sell.
|
||||
/// @param sellAmount Amount of tokens to sell.
|
||||
/// @param buyToken Token to buy.
|
||||
/// @param recipientAddress Address to send bought tokens to.
|
||||
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
|
||||
/// @param minConversionRate The minimal conversion rate. If actual rate
|
||||
/// is lower, trade is canceled.
|
||||
/// @param walletId The wallet ID to send part of the fees
|
||||
/// @param hint The hint for the selective inclusion (or exclusion) of reserves
|
||||
/// @return boughtAmount Amount of tokens bought.
|
||||
function tradeWithHint(
|
||||
IERC20TokenV06 sellToken,
|
||||
uint256 sellAmount,
|
||||
IERC20TokenV06 buyToken,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address payable walletId,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount);
|
||||
}
|
||||
|
||||
contract MixinKyber {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Address indicating the trade is using ETH
|
||||
IERC20TokenV06 private immutable KYBER_ETH_ADDRESS =
|
||||
IERC20TokenV06(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
{
|
||||
WETH = weth;
|
||||
}
|
||||
|
||||
function _tradeKyber(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(IKyberNetworkProxy kyber, bytes memory hint) =
|
||||
abi.decode(bridgeData, (IKyberNetworkProxy, bytes));
|
||||
|
||||
uint256 payableAmount = 0;
|
||||
if (sellToken != WETH) {
|
||||
// If the input token is not WETH, grant an allowance to the exchange
|
||||
// to spend them.
|
||||
sellToken.approveIfBelow(
|
||||
address(kyber),
|
||||
sellAmount
|
||||
);
|
||||
} else {
|
||||
// If the input token is WETH, unwrap it and attach it to the call.
|
||||
payableAmount = sellAmount;
|
||||
WETH.withdraw(payableAmount);
|
||||
}
|
||||
|
||||
// Try to sell all of this contract's input token balance through
|
||||
// `KyberNetworkProxy.trade()`.
|
||||
boughtAmount = kyber.tradeWithHint{ value: payableAmount }(
|
||||
// Input token.
|
||||
sellToken == WETH ? KYBER_ETH_ADDRESS : sellToken,
|
||||
// Sell amount.
|
||||
sellAmount,
|
||||
// Output token.
|
||||
buyToken == WETH ? KYBER_ETH_ADDRESS : buyToken,
|
||||
// Transfer to this contract
|
||||
address(uint160(address(this))),
|
||||
// Buy as much as possible.
|
||||
uint256(-1),
|
||||
// Lowest minimum conversion rate
|
||||
1,
|
||||
// No affiliate address.
|
||||
address(0),
|
||||
hint
|
||||
);
|
||||
// If receving ETH, wrap it to WETH.
|
||||
if (buyToken == WETH) {
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
}
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -26,7 +26,7 @@ import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
|
||||
|
||||
/// @dev Minimal interface for minting StETH
|
||||
interface ILido {
|
||||
interface IStETH {
|
||||
/// @dev Adds eth to the pool
|
||||
/// @param _referral optional address for referrals
|
||||
/// @return StETH Amount of shares generated
|
||||
@@ -37,6 +37,33 @@ interface ILido {
|
||||
function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);
|
||||
}
|
||||
|
||||
/// @dev Minimal interface for wrapping/unwrapping stETH.
|
||||
interface IWstETH {
|
||||
|
||||
/**
|
||||
* @notice Exchanges stETH to wstETH
|
||||
* @param _stETHAmount amount of stETH to wrap in exchange for wstETH
|
||||
* @dev Requirements:
|
||||
* - `_stETHAmount` must be non-zero
|
||||
* - msg.sender must approve at least `_stETHAmount` stETH to this
|
||||
* contract.
|
||||
* - msg.sender must have at least `_stETHAmount` of stETH.
|
||||
* User should first approve _stETHAmount to the WstETH contract
|
||||
* @return Amount of wstETH user receives after wrap
|
||||
*/
|
||||
function wrap(uint256 _stETHAmount) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Exchanges wstETH to stETH
|
||||
* @param _wstETHAmount amount of wstETH to uwrap in exchange for stETH
|
||||
* @dev Requirements:
|
||||
* - `_wstETHAmount` must be non-zero
|
||||
* - msg.sender must have at least `_wstETHAmount` wstETH.
|
||||
* @return Amount of stETH user receives after unwrap
|
||||
*/
|
||||
function unwrap(uint256 _wstETHAmount) external returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract MixinLido {
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
@@ -59,12 +86,43 @@ contract MixinLido {
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(ILido lido) = abi.decode(bridgeData, (ILido));
|
||||
if (address(sellToken) == address(WETH) && address(buyToken) == address(lido)) {
|
||||
if (address(sellToken) == address(WETH)) {
|
||||
return _tradeStETH(buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
return _tradeWstETH(sellToken, buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
function _tradeStETH(
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
) private returns (uint256 boughtAmount) {
|
||||
(IStETH stETH) = abi.decode(bridgeData, (IStETH));
|
||||
if (address(buyToken) == address(stETH)) {
|
||||
WETH.withdraw(sellAmount);
|
||||
boughtAmount = lido.getPooledEthByShares(lido.submit{ value: sellAmount}(address(0)));
|
||||
} else {
|
||||
revert("MixinLido/UNSUPPORTED_TOKEN_PAIR");
|
||||
return stETH.getPooledEthByShares(stETH.submit{ value: sellAmount}(address(0)));
|
||||
}
|
||||
|
||||
revert("MixinLido/UNSUPPORTED_TOKEN_PAIR");
|
||||
}
|
||||
|
||||
function _tradeWstETH(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
|
||||
) private returns(uint256 boughtAmount){
|
||||
(IEtherTokenV06 stETH, IWstETH wstETH) = abi.decode(bridgeData, (IEtherTokenV06, IWstETH));
|
||||
if (address(sellToken) == address(stETH) && address(buyToken) == address(wstETH) ) {
|
||||
sellToken.approveIfBelow(address(wstETH), sellAmount);
|
||||
return wstETH.wrap(sellAmount);
|
||||
}
|
||||
if (address(sellToken) == address(wstETH) && address(buyToken) == address(stETH) ) {
|
||||
return wstETH.unwrap(sellAmount);
|
||||
}
|
||||
|
||||
revert("MixinLido/UNSUPPORTED_TOKEN_PAIR");
|
||||
}
|
||||
}
|
||||
|
@@ -1,76 +0,0 @@
|
||||
// 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";
|
||||
import "../IBridgeAdapter.sol";
|
||||
|
||||
interface IOasis {
|
||||
|
||||
/// @dev Sell `sellAmount` of `sellToken` token and receive `buyToken` token.
|
||||
/// @param sellToken The token being sold.
|
||||
/// @param sellAmount The amount of `sellToken` token being sold.
|
||||
/// @param buyToken The token being bought.
|
||||
/// @param minBoughtAmount Minimum amount of `buyToken` token to buy.
|
||||
/// @return boughtAmount Amount of `buyToken` bought.
|
||||
function sellAllAmount(
|
||||
IERC20TokenV06 sellToken,
|
||||
uint256 sellAmount,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 minBoughtAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount);
|
||||
}
|
||||
|
||||
contract MixinOasis {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeOasis(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
|
||||
(IOasis oasis) = abi.decode(bridgeData, (IOasis));
|
||||
|
||||
// Grant an allowance to the exchange to spend `sellToken` token.
|
||||
sellToken.approveIfBelow(
|
||||
address(oasis),
|
||||
sellAmount
|
||||
);
|
||||
// Try to sell all of this contract's `sellToken` token balance.
|
||||
boughtAmount = oasis.sellAllAmount(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
buyToken,
|
||||
// min fill amount
|
||||
1
|
||||
);
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
|
||||
|
||||
interface IPlatypusRouter {
|
||||
|
||||
function swapTokensForTokens(
|
||||
address[] calldata tokenPath,
|
||||
address[] calldata poolPath,
|
||||
uint256 fromAmount,
|
||||
uint256 minimumToAmount,
|
||||
address to,
|
||||
uint256 deadline
|
||||
) external returns (uint256 amountOut, uint256 haircut);
|
||||
}
|
||||
|
||||
contract MixinPlatypus {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
function _tradePlatypus(
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
public
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
IPlatypusRouter router;
|
||||
address _router;
|
||||
address[] memory _pool;
|
||||
IERC20TokenV06[] memory path;
|
||||
address[] memory _path;
|
||||
|
||||
{
|
||||
(_router, _pool, _path) = abi.decode(bridgeData, (address, address[], address[]));
|
||||
|
||||
// To get around `abi.decode()` not supporting interface array types.
|
||||
assembly { path := _path }
|
||||
}
|
||||
|
||||
//connect to the ptp router
|
||||
router = IPlatypusRouter(_router);
|
||||
|
||||
require(path.length >= 2, "MixinPlatypus/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(
|
||||
path[path.length - 1] == buyToken,
|
||||
"MixinPlatypus/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
|
||||
);
|
||||
// Grant the Platypus router an allowance to sell the first token.
|
||||
path[0].approveIfBelow(address(router), sellAmount);
|
||||
|
||||
//keep track of the previous balance to confirm amount out
|
||||
uint256 beforeBalance = buyToken.balanceOf(address(this));
|
||||
|
||||
router.swapTokensForTokens(
|
||||
// Convert to `buyToken` along this path.
|
||||
_path,
|
||||
// pool to swap on
|
||||
_pool,
|
||||
// Sell all tokens we hold.
|
||||
sellAmount,
|
||||
// Minimum buy amount.
|
||||
0,
|
||||
// Recipient is `this`.
|
||||
address(this),
|
||||
|
||||
block.timestamp + 1
|
||||
);
|
||||
//calculate the buy amount from the tokens we recieved
|
||||
boughtAmount = buyToken.balanceOf(address(this)).safeSub(beforeBalance);
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 IVelodromeRouter {
|
||||
function swapExactTokensForTokensSimple(
|
||||
uint256 amountIn,
|
||||
uint256 amountOutMin,
|
||||
address tokenFrom,
|
||||
address tokenTo,
|
||||
bool stable,
|
||||
address to,
|
||||
uint256 deadline
|
||||
) external returns (uint256[] memory amounts);
|
||||
}
|
||||
|
||||
contract MixinVelodrome {
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeVelodrome(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
|
||||
(IVelodromeRouter router, bool stable) = abi.decode(bridgeData, (IVelodromeRouter, bool));
|
||||
sellToken.approveIfBelow(address(router), sellAmount);
|
||||
|
||||
boughtAmount = router.swapExactTokensForTokensSimple(
|
||||
sellAmount,
|
||||
0,
|
||||
address(sellToken),
|
||||
address(buyToken),
|
||||
stable,
|
||||
address(this),
|
||||
block.timestamp + 1
|
||||
)[1];
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-zero-ex",
|
||||
"version": "0.31.1",
|
||||
"version": "0.35.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -41,9 +41,9 @@
|
||||
"rollback": "node ./lib/scripts/rollback.js"
|
||||
},
|
||||
"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,OtcOrdersFeature,IOtcOrdersFeature",
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature,AvalancheBridgeAdapter,BSCBridgeAdapter,CeloBridgeAdapter,EthereumBridgeAdapter,FantomBridgeAdapter,OptimismBridgeAdapter,PolygonBridgeAdapter",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
"abis": "./test/generated-artifacts/@(AbstractBridgeAdapter|AffiliateFeeTransformer|AvalancheBridgeAdapter|BSCBridgeAdapter|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeProtocols|CeloBridgeAdapter|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|EthereumBridgeAdapter|FantomBridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBalancerV2Batch|MixinBancor|MixinBancorV3|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinPlatypus|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinVelodrome|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OptimismBridgeAdapter|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PolygonBridgeAdapter|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|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.7.2",
|
||||
"@0x/contract-addresses": "^6.12.0",
|
||||
"@0x/contracts-erc20": "^3.3.27",
|
||||
"@0x/contracts-gen": "^2.0.43",
|
||||
"@0x/contracts-test-utils": "^5.4.18",
|
||||
"@0x/dev-utils": "^4.2.11",
|
||||
"@0x/abi-gen": "^5.8.0",
|
||||
"@0x/contract-addresses": "^6.16.0",
|
||||
"@0x/contracts-erc20": "^3.3.32",
|
||||
"@0x/contracts-gen": "^2.0.46",
|
||||
"@0x/contracts-test-utils": "^5.4.23",
|
||||
"@0x/dev-utils": "^4.2.14",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-compiler": "^4.7.8",
|
||||
"@0x/sol-compiler": "^4.8.1",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@types/isomorphic-fetch": "^0.0.35",
|
||||
@@ -79,17 +79,17 @@
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "4.2.2"
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.5",
|
||||
"@0x/protocol-utils": "^1.11.1",
|
||||
"@0x/subproviders": "^6.6.2",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.5.0",
|
||||
"@0x/web3-wrapper": "^7.6.2",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"@0x/base-contract": "^6.5.0",
|
||||
"@0x/protocol-utils": "^11.15.0",
|
||||
"@0x/subproviders": "^6.6.5",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
"@0x/utils": "^6.5.3",
|
||||
"@0x/web3-wrapper": "^7.6.5",
|
||||
"ethereum-types": "^3.7.0",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"ethers": "~4.0.4"
|
||||
},
|
||||
|
@@ -6,9 +6,13 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as AffiliateFeeTransformer from '../generated-artifacts/AffiliateFeeTransformer.json';
|
||||
import * as AvalancheBridgeAdapter from '../generated-artifacts/AvalancheBridgeAdapter.json';
|
||||
import * as BatchFillNativeOrdersFeature from '../generated-artifacts/BatchFillNativeOrdersFeature.json';
|
||||
import * as BridgeAdapter from '../generated-artifacts/BridgeAdapter.json';
|
||||
import * as BSCBridgeAdapter from '../generated-artifacts/BSCBridgeAdapter.json';
|
||||
import * as CeloBridgeAdapter from '../generated-artifacts/CeloBridgeAdapter.json';
|
||||
import * as CurveLiquidityProvider from '../generated-artifacts/CurveLiquidityProvider.json';
|
||||
import * as EthereumBridgeAdapter from '../generated-artifacts/EthereumBridgeAdapter.json';
|
||||
import * as FantomBridgeAdapter from '../generated-artifacts/FantomBridgeAdapter.json';
|
||||
import * as FeeCollector from '../generated-artifacts/FeeCollector.json';
|
||||
import * as FeeCollectorController from '../generated-artifacts/FeeCollectorController.json';
|
||||
import * as FillQuoteTransformer from '../generated-artifacts/FillQuoteTransformer.json';
|
||||
@@ -30,9 +34,11 @@ import * as LogMetadataTransformer from '../generated-artifacts/LogMetadataTrans
|
||||
import * as MetaTransactionsFeature from '../generated-artifacts/MetaTransactionsFeature.json';
|
||||
import * as MultiplexFeature from '../generated-artifacts/MultiplexFeature.json';
|
||||
import * as NativeOrdersFeature from '../generated-artifacts/NativeOrdersFeature.json';
|
||||
import * as OptimismBridgeAdapter from '../generated-artifacts/OptimismBridgeAdapter.json';
|
||||
import * as OtcOrdersFeature from '../generated-artifacts/OtcOrdersFeature.json';
|
||||
import * as OwnableFeature from '../generated-artifacts/OwnableFeature.json';
|
||||
import * as PayTakerTransformer from '../generated-artifacts/PayTakerTransformer.json';
|
||||
import * as PolygonBridgeAdapter from '../generated-artifacts/PolygonBridgeAdapter.json';
|
||||
import * as PositiveSlippageFeeTransformer from '../generated-artifacts/PositiveSlippageFeeTransformer.json';
|
||||
import * as SimpleFunctionRegistryFeature from '../generated-artifacts/SimpleFunctionRegistryFeature.json';
|
||||
import * as TransformERC20Feature from '../generated-artifacts/TransformERC20Feature.json';
|
||||
@@ -58,7 +64,6 @@ export const artifacts = {
|
||||
AffiliateFeeTransformer: AffiliateFeeTransformer as ContractArtifact,
|
||||
MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact,
|
||||
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
|
||||
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
||||
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
|
||||
ILiquidityProviderFeature: ILiquidityProviderFeature as ContractArtifact,
|
||||
NativeOrdersFeature: NativeOrdersFeature as ContractArtifact,
|
||||
@@ -72,4 +77,11 @@ export const artifacts = {
|
||||
IMultiplexFeature: IMultiplexFeature as ContractArtifact,
|
||||
OtcOrdersFeature: OtcOrdersFeature as ContractArtifact,
|
||||
IOtcOrdersFeature: IOtcOrdersFeature as ContractArtifact,
|
||||
AvalancheBridgeAdapter: AvalancheBridgeAdapter as ContractArtifact,
|
||||
BSCBridgeAdapter: BSCBridgeAdapter as ContractArtifact,
|
||||
CeloBridgeAdapter: CeloBridgeAdapter as ContractArtifact,
|
||||
EthereumBridgeAdapter: EthereumBridgeAdapter as ContractArtifact,
|
||||
FantomBridgeAdapter: FantomBridgeAdapter as ContractArtifact,
|
||||
OptimismBridgeAdapter: OptimismBridgeAdapter as ContractArtifact,
|
||||
PolygonBridgeAdapter: PolygonBridgeAdapter as ContractArtifact,
|
||||
};
|
||||
|
@@ -35,7 +35,11 @@ export * from './bloom_filter_utils';
|
||||
export { GREEDY_TOKENS } from './constants';
|
||||
export {
|
||||
AffiliateFeeTransformerContract,
|
||||
BridgeAdapterContract,
|
||||
AvalancheBridgeAdapterContract,
|
||||
BSCBridgeAdapterContract,
|
||||
CeloBridgeAdapterContract,
|
||||
EthereumBridgeAdapterContract,
|
||||
FantomBridgeAdapterContract,
|
||||
FillQuoteTransformerContract,
|
||||
IOwnableFeatureContract,
|
||||
IOwnableFeatureEvents,
|
||||
@@ -45,7 +49,9 @@ export {
|
||||
IZeroExContract,
|
||||
LogMetadataTransformerContract,
|
||||
MultiplexFeatureContract,
|
||||
OptimismBridgeAdapterContract,
|
||||
PayTakerTransformerContract,
|
||||
PolygonBridgeAdapterContract,
|
||||
PositiveSlippageFeeTransformerContract,
|
||||
TransformERC20FeatureContract,
|
||||
WethTransformerContract,
|
||||
|
@@ -4,9 +4,13 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/affiliate_fee_transformer';
|
||||
export * from '../generated-wrappers/avalanche_bridge_adapter';
|
||||
export * from '../generated-wrappers/b_s_c_bridge_adapter';
|
||||
export * from '../generated-wrappers/batch_fill_native_orders_feature';
|
||||
export * from '../generated-wrappers/bridge_adapter';
|
||||
export * from '../generated-wrappers/celo_bridge_adapter';
|
||||
export * from '../generated-wrappers/curve_liquidity_provider';
|
||||
export * from '../generated-wrappers/ethereum_bridge_adapter';
|
||||
export * from '../generated-wrappers/fantom_bridge_adapter';
|
||||
export * from '../generated-wrappers/fee_collector';
|
||||
export * from '../generated-wrappers/fee_collector_controller';
|
||||
export * from '../generated-wrappers/fill_quote_transformer';
|
||||
@@ -28,9 +32,11 @@ export * from '../generated-wrappers/log_metadata_transformer';
|
||||
export * from '../generated-wrappers/meta_transactions_feature';
|
||||
export * from '../generated-wrappers/multiplex_feature';
|
||||
export * from '../generated-wrappers/native_orders_feature';
|
||||
export * from '../generated-wrappers/optimism_bridge_adapter';
|
||||
export * from '../generated-wrappers/otc_orders_feature';
|
||||
export * from '../generated-wrappers/ownable_feature';
|
||||
export * from '../generated-wrappers/pay_taker_transformer';
|
||||
export * from '../generated-wrappers/polygon_bridge_adapter';
|
||||
export * from '../generated-wrappers/positive_slippage_fee_transformer';
|
||||
export * from '../generated-wrappers/simple_function_registry_feature';
|
||||
export * from '../generated-wrappers/transform_erc20_feature';
|
||||
|
@@ -5,15 +5,20 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as AbstractBridgeAdapter from '../test/generated-artifacts/AbstractBridgeAdapter.json';
|
||||
import * as AffiliateFeeTransformer from '../test/generated-artifacts/AffiliateFeeTransformer.json';
|
||||
import * as AvalancheBridgeAdapter from '../test/generated-artifacts/AvalancheBridgeAdapter.json';
|
||||
import * as BatchFillNativeOrdersFeature from '../test/generated-artifacts/BatchFillNativeOrdersFeature.json';
|
||||
import * as BootstrapFeature from '../test/generated-artifacts/BootstrapFeature.json';
|
||||
import * as BridgeAdapter from '../test/generated-artifacts/BridgeAdapter.json';
|
||||
import * as BridgeProtocols from '../test/generated-artifacts/BridgeProtocols.json';
|
||||
import * as BSCBridgeAdapter from '../test/generated-artifacts/BSCBridgeAdapter.json';
|
||||
import * as CeloBridgeAdapter from '../test/generated-artifacts/CeloBridgeAdapter.json';
|
||||
import * as CurveLiquidityProvider from '../test/generated-artifacts/CurveLiquidityProvider.json';
|
||||
import * as ERC1155OrdersFeature from '../test/generated-artifacts/ERC1155OrdersFeature.json';
|
||||
import * as ERC165Feature from '../test/generated-artifacts/ERC165Feature.json';
|
||||
import * as ERC721OrdersFeature from '../test/generated-artifacts/ERC721OrdersFeature.json';
|
||||
import * as EthereumBridgeAdapter from '../test/generated-artifacts/EthereumBridgeAdapter.json';
|
||||
import * as FantomBridgeAdapter from '../test/generated-artifacts/FantomBridgeAdapter.json';
|
||||
import * as FeeCollector from '../test/generated-artifacts/FeeCollector.json';
|
||||
import * as FeeCollectorController from '../test/generated-artifacts/FeeCollectorController.json';
|
||||
import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json';
|
||||
@@ -101,26 +106,28 @@ import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransa
|
||||
import * as MixinAaveV2 from '../test/generated-artifacts/MixinAaveV2.json';
|
||||
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
|
||||
import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json';
|
||||
import * as MixinBalancerV2Batch from '../test/generated-artifacts/MixinBalancerV2Batch.json';
|
||||
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
|
||||
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
|
||||
import * as MixinBancorV3 from '../test/generated-artifacts/MixinBancorV3.json';
|
||||
import * as MixinCompound from '../test/generated-artifacts/MixinCompound.json';
|
||||
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
|
||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||
import * as MixinCurveV2 from '../test/generated-artifacts/MixinCurveV2.json';
|
||||
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
|
||||
import * as MixinDodoV2 from '../test/generated-artifacts/MixinDodoV2.json';
|
||||
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
|
||||
import * as MixinGMX from '../test/generated-artifacts/MixinGMX.json';
|
||||
import * as MixinKyberDmm from '../test/generated-artifacts/MixinKyberDmm.json';
|
||||
import * as MixinLido from '../test/generated-artifacts/MixinLido.json';
|
||||
import * as MixinMakerPSM from '../test/generated-artifacts/MixinMakerPSM.json';
|
||||
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
|
||||
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
|
||||
import * as MixinNerve from '../test/generated-artifacts/MixinNerve.json';
|
||||
import * as MixinOasis from '../test/generated-artifacts/MixinOasis.json';
|
||||
import * as MixinPlatypus from '../test/generated-artifacts/MixinPlatypus.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 MixinVelodrome from '../test/generated-artifacts/MixinVelodrome.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';
|
||||
@@ -136,11 +143,13 @@ import * as NativeOrdersInfo from '../test/generated-artifacts/NativeOrdersInfo.
|
||||
import * as NativeOrdersProtocolFees from '../test/generated-artifacts/NativeOrdersProtocolFees.json';
|
||||
import * as NativeOrdersSettlement from '../test/generated-artifacts/NativeOrdersSettlement.json';
|
||||
import * as NFTOrders from '../test/generated-artifacts/NFTOrders.json';
|
||||
import * as OptimismBridgeAdapter from '../test/generated-artifacts/OptimismBridgeAdapter.json';
|
||||
import * as OtcOrdersFeature from '../test/generated-artifacts/OtcOrdersFeature.json';
|
||||
import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json';
|
||||
import * as PancakeSwapFeature from '../test/generated-artifacts/PancakeSwapFeature.json';
|
||||
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
|
||||
import * as PermissionlessTransformerDeployer from '../test/generated-artifacts/PermissionlessTransformerDeployer.json';
|
||||
import * as PolygonBridgeAdapter from '../test/generated-artifacts/PolygonBridgeAdapter.json';
|
||||
import * as PositiveSlippageFeeTransformer from '../test/generated-artifacts/PositiveSlippageFeeTransformer.json';
|
||||
import * as SimpleFunctionRegistryFeature from '../test/generated-artifacts/SimpleFunctionRegistryFeature.json';
|
||||
import * as TestBridge from '../test/generated-artifacts/TestBridge.json';
|
||||
@@ -307,32 +316,41 @@ export const artifacts = {
|
||||
PositiveSlippageFeeTransformer: PositiveSlippageFeeTransformer as ContractArtifact,
|
||||
Transformer: Transformer as ContractArtifact,
|
||||
WethTransformer: WethTransformer as ContractArtifact,
|
||||
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
||||
AbstractBridgeAdapter: AbstractBridgeAdapter as ContractArtifact,
|
||||
AvalancheBridgeAdapter: AvalancheBridgeAdapter as ContractArtifact,
|
||||
BSCBridgeAdapter: BSCBridgeAdapter as ContractArtifact,
|
||||
BridgeProtocols: BridgeProtocols as ContractArtifact,
|
||||
CeloBridgeAdapter: CeloBridgeAdapter as ContractArtifact,
|
||||
EthereumBridgeAdapter: EthereumBridgeAdapter as ContractArtifact,
|
||||
FantomBridgeAdapter: FantomBridgeAdapter as ContractArtifact,
|
||||
IBridgeAdapter: IBridgeAdapter as ContractArtifact,
|
||||
OptimismBridgeAdapter: OptimismBridgeAdapter as ContractArtifact,
|
||||
PolygonBridgeAdapter: PolygonBridgeAdapter as ContractArtifact,
|
||||
MixinAaveV2: MixinAaveV2 as ContractArtifact,
|
||||
MixinBalancer: MixinBalancer as ContractArtifact,
|
||||
MixinBalancerV2: MixinBalancerV2 as ContractArtifact,
|
||||
MixinBalancerV2Batch: MixinBalancerV2Batch as ContractArtifact,
|
||||
MixinBancor: MixinBancor as ContractArtifact,
|
||||
MixinCoFiX: MixinCoFiX as ContractArtifact,
|
||||
MixinBancorV3: MixinBancorV3 as ContractArtifact,
|
||||
MixinCompound: MixinCompound as ContractArtifact,
|
||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
MixinCurveV2: MixinCurveV2 as ContractArtifact,
|
||||
MixinDodo: MixinDodo as ContractArtifact,
|
||||
MixinDodoV2: MixinDodoV2 as ContractArtifact,
|
||||
MixinKyber: MixinKyber as ContractArtifact,
|
||||
MixinGMX: MixinGMX as ContractArtifact,
|
||||
MixinKyberDmm: MixinKyberDmm as ContractArtifact,
|
||||
MixinLido: MixinLido as ContractArtifact,
|
||||
MixinMStable: MixinMStable as ContractArtifact,
|
||||
MixinMakerPSM: MixinMakerPSM as ContractArtifact,
|
||||
MixinMooniswap: MixinMooniswap as ContractArtifact,
|
||||
MixinNerve: MixinNerve as ContractArtifact,
|
||||
MixinOasis: MixinOasis as ContractArtifact,
|
||||
MixinPlatypus: MixinPlatypus as ContractArtifact,
|
||||
MixinShell: MixinShell as ContractArtifact,
|
||||
MixinUniswap: MixinUniswap as ContractArtifact,
|
||||
MixinUniswapV2: MixinUniswapV2 as ContractArtifact,
|
||||
MixinUniswapV3: MixinUniswapV3 as ContractArtifact,
|
||||
MixinVelodrome: MixinVelodrome as ContractArtifact,
|
||||
MixinZeroExBridge: MixinZeroExBridge as ContractArtifact,
|
||||
IERC1155Token: IERC1155Token as ContractArtifact,
|
||||
IERC721Token: IERC721Token as ContractArtifact,
|
||||
|
@@ -28,7 +28,7 @@ import { artifacts } from '../artifacts';
|
||||
import { TestFillQuoteTransformerBridgeContract } from '../generated-wrappers/test_fill_quote_transformer_bridge';
|
||||
import { getRandomLimitOrder, getRandomRfqOrder } from '../utils/orders';
|
||||
import {
|
||||
BridgeAdapterContract,
|
||||
EthereumBridgeAdapterContract,
|
||||
FillQuoteTransformerContract,
|
||||
TestFillQuoteTransformerExchangeContract,
|
||||
TestFillQuoteTransformerHostContract,
|
||||
@@ -52,7 +52,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
let singleProtocolFee: BigNumber;
|
||||
|
||||
const GAS_PRICE = 1337;
|
||||
const TEST_BRIDGE_SOURCE = hexUtils.random(32);
|
||||
// Left half is 0, corresponding to BridgeProtocol.Unknown
|
||||
const TEST_BRIDGE_SOURCE = hexUtils.leftPad(hexUtils.random(16), 32);
|
||||
const HIGH_BIT = new BigNumber(2).pow(255);
|
||||
const REVERT_AMOUNT = new BigNumber('0xdeadbeef');
|
||||
|
||||
@@ -64,8 +65,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const bridgeAdapter = await BridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
artifacts.BridgeAdapter,
|
||||
const bridgeAdapter = await EthereumBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
artifacts.EthereumBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
|
@@ -3,15 +3,20 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/abstract_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/affiliate_fee_transformer';
|
||||
export * from '../test/generated-wrappers/avalanche_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/b_s_c_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/batch_fill_native_orders_feature';
|
||||
export * from '../test/generated-wrappers/bootstrap_feature';
|
||||
export * from '../test/generated-wrappers/bridge_adapter';
|
||||
export * from '../test/generated-wrappers/bridge_protocols';
|
||||
export * from '../test/generated-wrappers/celo_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/curve_liquidity_provider';
|
||||
export * from '../test/generated-wrappers/erc1155_orders_feature';
|
||||
export * from '../test/generated-wrappers/erc165_feature';
|
||||
export * from '../test/generated-wrappers/erc721_orders_feature';
|
||||
export * from '../test/generated-wrappers/ethereum_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/fantom_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/fee_collector';
|
||||
export * from '../test/generated-wrappers/fee_collector_controller';
|
||||
export * from '../test/generated-wrappers/fill_quote_transformer';
|
||||
@@ -99,26 +104,28 @@ export * from '../test/generated-wrappers/meta_transactions_feature';
|
||||
export * from '../test/generated-wrappers/mixin_aave_v2';
|
||||
export * from '../test/generated-wrappers/mixin_balancer';
|
||||
export * from '../test/generated-wrappers/mixin_balancer_v2';
|
||||
export * from '../test/generated-wrappers/mixin_balancer_v2_batch';
|
||||
export * from '../test/generated-wrappers/mixin_bancor';
|
||||
export * from '../test/generated-wrappers/mixin_co_fi_x';
|
||||
export * from '../test/generated-wrappers/mixin_bancor_v3';
|
||||
export * from '../test/generated-wrappers/mixin_compound';
|
||||
export * from '../test/generated-wrappers/mixin_crypto_com';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
export * from '../test/generated-wrappers/mixin_curve_v2';
|
||||
export * from '../test/generated-wrappers/mixin_dodo';
|
||||
export * from '../test/generated-wrappers/mixin_dodo_v2';
|
||||
export * from '../test/generated-wrappers/mixin_kyber';
|
||||
export * from '../test/generated-wrappers/mixin_g_m_x';
|
||||
export * from '../test/generated-wrappers/mixin_kyber_dmm';
|
||||
export * from '../test/generated-wrappers/mixin_lido';
|
||||
export * from '../test/generated-wrappers/mixin_m_stable';
|
||||
export * from '../test/generated-wrappers/mixin_maker_p_s_m';
|
||||
export * from '../test/generated-wrappers/mixin_mooniswap';
|
||||
export * from '../test/generated-wrappers/mixin_nerve';
|
||||
export * from '../test/generated-wrappers/mixin_oasis';
|
||||
export * from '../test/generated-wrappers/mixin_platypus';
|
||||
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_velodrome';
|
||||
export * from '../test/generated-wrappers/mixin_zero_ex_bridge';
|
||||
export * from '../test/generated-wrappers/mooniswap_liquidity_provider';
|
||||
export * from '../test/generated-wrappers/multiplex_feature';
|
||||
@@ -134,11 +141,13 @@ export * from '../test/generated-wrappers/native_orders_feature';
|
||||
export * from '../test/generated-wrappers/native_orders_info';
|
||||
export * from '../test/generated-wrappers/native_orders_protocol_fees';
|
||||
export * from '../test/generated-wrappers/native_orders_settlement';
|
||||
export * from '../test/generated-wrappers/optimism_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/otc_orders_feature';
|
||||
export * from '../test/generated-wrappers/ownable_feature';
|
||||
export * from '../test/generated-wrappers/pancake_swap_feature';
|
||||
export * from '../test/generated-wrappers/pay_taker_transformer';
|
||||
export * from '../test/generated-wrappers/permissionless_transformer_deployer';
|
||||
export * from '../test/generated-wrappers/polygon_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/positive_slippage_fee_transformer';
|
||||
export * from '../test/generated-wrappers/simple_function_registry_feature';
|
||||
export * from '../test/generated-wrappers/test_bridge';
|
||||
|
@@ -4,9 +4,13 @@
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*", "./scripts/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/AffiliateFeeTransformer.json",
|
||||
"generated-artifacts/AvalancheBridgeAdapter.json",
|
||||
"generated-artifacts/BSCBridgeAdapter.json",
|
||||
"generated-artifacts/BatchFillNativeOrdersFeature.json",
|
||||
"generated-artifacts/BridgeAdapter.json",
|
||||
"generated-artifacts/CeloBridgeAdapter.json",
|
||||
"generated-artifacts/CurveLiquidityProvider.json",
|
||||
"generated-artifacts/EthereumBridgeAdapter.json",
|
||||
"generated-artifacts/FantomBridgeAdapter.json",
|
||||
"generated-artifacts/FeeCollector.json",
|
||||
"generated-artifacts/FeeCollectorController.json",
|
||||
"generated-artifacts/FillQuoteTransformer.json",
|
||||
@@ -28,23 +32,30 @@
|
||||
"generated-artifacts/MetaTransactionsFeature.json",
|
||||
"generated-artifacts/MultiplexFeature.json",
|
||||
"generated-artifacts/NativeOrdersFeature.json",
|
||||
"generated-artifacts/OptimismBridgeAdapter.json",
|
||||
"generated-artifacts/OtcOrdersFeature.json",
|
||||
"generated-artifacts/OwnableFeature.json",
|
||||
"generated-artifacts/PayTakerTransformer.json",
|
||||
"generated-artifacts/PolygonBridgeAdapter.json",
|
||||
"generated-artifacts/PositiveSlippageFeeTransformer.json",
|
||||
"generated-artifacts/SimpleFunctionRegistryFeature.json",
|
||||
"generated-artifacts/TransformERC20Feature.json",
|
||||
"generated-artifacts/WethTransformer.json",
|
||||
"generated-artifacts/ZeroEx.json",
|
||||
"test/generated-artifacts/AbstractBridgeAdapter.json",
|
||||
"test/generated-artifacts/AffiliateFeeTransformer.json",
|
||||
"test/generated-artifacts/AvalancheBridgeAdapter.json",
|
||||
"test/generated-artifacts/BSCBridgeAdapter.json",
|
||||
"test/generated-artifacts/BatchFillNativeOrdersFeature.json",
|
||||
"test/generated-artifacts/BootstrapFeature.json",
|
||||
"test/generated-artifacts/BridgeAdapter.json",
|
||||
"test/generated-artifacts/BridgeProtocols.json",
|
||||
"test/generated-artifacts/CeloBridgeAdapter.json",
|
||||
"test/generated-artifacts/CurveLiquidityProvider.json",
|
||||
"test/generated-artifacts/ERC1155OrdersFeature.json",
|
||||
"test/generated-artifacts/ERC165Feature.json",
|
||||
"test/generated-artifacts/ERC721OrdersFeature.json",
|
||||
"test/generated-artifacts/EthereumBridgeAdapter.json",
|
||||
"test/generated-artifacts/FantomBridgeAdapter.json",
|
||||
"test/generated-artifacts/FeeCollector.json",
|
||||
"test/generated-artifacts/FeeCollectorController.json",
|
||||
"test/generated-artifacts/FillQuoteTransformer.json",
|
||||
@@ -132,26 +143,28 @@
|
||||
"test/generated-artifacts/MixinAaveV2.json",
|
||||
"test/generated-artifacts/MixinBalancer.json",
|
||||
"test/generated-artifacts/MixinBalancerV2.json",
|
||||
"test/generated-artifacts/MixinBalancerV2Batch.json",
|
||||
"test/generated-artifacts/MixinBancor.json",
|
||||
"test/generated-artifacts/MixinCoFiX.json",
|
||||
"test/generated-artifacts/MixinBancorV3.json",
|
||||
"test/generated-artifacts/MixinCompound.json",
|
||||
"test/generated-artifacts/MixinCryptoCom.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
"test/generated-artifacts/MixinCurveV2.json",
|
||||
"test/generated-artifacts/MixinDodo.json",
|
||||
"test/generated-artifacts/MixinDodoV2.json",
|
||||
"test/generated-artifacts/MixinKyber.json",
|
||||
"test/generated-artifacts/MixinGMX.json",
|
||||
"test/generated-artifacts/MixinKyberDmm.json",
|
||||
"test/generated-artifacts/MixinLido.json",
|
||||
"test/generated-artifacts/MixinMStable.json",
|
||||
"test/generated-artifacts/MixinMakerPSM.json",
|
||||
"test/generated-artifacts/MixinMooniswap.json",
|
||||
"test/generated-artifacts/MixinNerve.json",
|
||||
"test/generated-artifacts/MixinOasis.json",
|
||||
"test/generated-artifacts/MixinPlatypus.json",
|
||||
"test/generated-artifacts/MixinShell.json",
|
||||
"test/generated-artifacts/MixinUniswap.json",
|
||||
"test/generated-artifacts/MixinUniswapV2.json",
|
||||
"test/generated-artifacts/MixinUniswapV3.json",
|
||||
"test/generated-artifacts/MixinVelodrome.json",
|
||||
"test/generated-artifacts/MixinZeroExBridge.json",
|
||||
"test/generated-artifacts/MooniswapLiquidityProvider.json",
|
||||
"test/generated-artifacts/MultiplexFeature.json",
|
||||
@@ -167,11 +180,13 @@
|
||||
"test/generated-artifacts/NativeOrdersInfo.json",
|
||||
"test/generated-artifacts/NativeOrdersProtocolFees.json",
|
||||
"test/generated-artifacts/NativeOrdersSettlement.json",
|
||||
"test/generated-artifacts/OptimismBridgeAdapter.json",
|
||||
"test/generated-artifacts/OtcOrdersFeature.json",
|
||||
"test/generated-artifacts/OwnableFeature.json",
|
||||
"test/generated-artifacts/PancakeSwapFeature.json",
|
||||
"test/generated-artifacts/PayTakerTransformer.json",
|
||||
"test/generated-artifacts/PermissionlessTransformerDeployer.json",
|
||||
"test/generated-artifacts/PolygonBridgeAdapter.json",
|
||||
"test/generated-artifacts/PositiveSlippageFeeTransformer.json",
|
||||
"test/generated-artifacts/SimpleFunctionRegistryFeature.json",
|
||||
"test/generated-artifacts/TestBridge.json",
|
||||
|
@@ -4,23 +4,28 @@ Audits
|
||||
|
||||
Below are links to our third-party audit reports.
|
||||
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| **Release** | **Reports** |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| Exchange V4 | * `Consensys Diligence (December 2020) <https://consensys.net/diligence/audits/2020/12/0x-exchange-v4/>`__ |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| Exchange V3 | * `Trail of Bits <http://zeips.0x.org.s3-website.us-east-2.amazonaws.com/audits/56/trail-of-bits/audit.pdf>`_ |
|
||||
| | * `Consensys Diligence (Exchange) <https://diligence.consensys.net/audits/2019/09/0x-v3-exchange/>`__ |
|
||||
| | * `Consensys Diligence (Staking) <https://diligence.consensys.net/audits/2019/10/0x-v3-staking/>`__ |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| Exchange V2.1 | * `First <https://docs.google.com/document/d/1jYv6V21MfCSwCS5fxD6ZyaLWGzkpRSUO0lZpST94XsA/edit>`_ |
|
||||
| | * `Consensys Diligence <https://github.com/ConsenSys/0x_audit_report_2018-07-23>`_ |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| MultiAssetProxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2018-12>`__ |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| ERC1155Proxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2019-05>`__ |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| StaticCallProxy | * No third-party audit. |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
| ERC20BridgeProxy | * No third-party audit. |
|
||||
+------------------+---------------------------------------------------------------------------------------------------------------+
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| **Release** | **Reports** |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| ERC721OrdersFeature | * `ABDK Consulting <https://s3.us-east-2.amazonaws.com/zeips.0x.org/audits/abdk-consulting/ABDK_0x_Solidity_v_1_0.pdf>`__ |
|
||||
| | |
|
||||
| | |
|
||||
| ERC1155OrdersFeature | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| Exchange V4 | * `Consensys Diligence (December 2020) <https://consensys.net/diligence/audits/2020/12/0x-exchange-v4/>`__ |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| Exchange V3 | * `Trail of Bits <http://zeips.0x.org.s3-website.us-east-2.amazonaws.com/audits/56/trail-of-bits/audit.pdf>`__ |
|
||||
| | * `Consensys Diligence (Exchange) <https://diligence.consensys.net/audits/2019/09/0x-v3-exchange/>`__ |
|
||||
| | * `Consensys Diligence (Staking) <https://diligence.consensys.net/audits/2019/10/0x-v3-staking/>`__ |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| Exchange V2.1 | * `First <https://docs.google.com/document/d/1jYv6V21MfCSwCS5fxD6ZyaLWGzkpRSUO0lZpST94XsA/edit>`_ |
|
||||
| | * `Consensys Diligence <https://github.com/ConsenSys/0x_audit_report_2018-07-23>`_ |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| MultiAssetProxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2018-12>`__ |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| ERC1155Proxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2019-05>`__ |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| StaticCallProxy | * No third-party audit. |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| ERC20BridgeProxy | * No third-party audit. |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
|
11
package.json
11
package.json
@@ -52,16 +52,16 @@
|
||||
},
|
||||
"config": {
|
||||
"contractsPackages": "@0x/contracts-erc20 @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-zero-ex @0x/contracts-treasury",
|
||||
"nonContractPackages": "@0x/migrations @0x/contract-wrappers @0x/contract-addresses @0x/contract-artifacts @0x/contract-wrappers-test @0x/asset-swapper",
|
||||
"nonContractPackages": "@0x/contract-wrappers @0x/contract-addresses @0x/contract-artifacts @0x/contract-wrappers-test @0x/asset-swapper",
|
||||
"ignoreTestsForPackages": "",
|
||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic",
|
||||
"packagesWithDocPages": "@0x/contract-wrappers @0x/migrations",
|
||||
"packagesWithDocPages": "@0x/contract-wrappers",
|
||||
"ignoreDependencyVersions": "@types/styled-components @types/node",
|
||||
"ignoreDependencyVersionsForPackage": "contract-wrappers"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0x/monorepo-scripts": "^3.2.1",
|
||||
"@0x-lerna-fork/lerna": "3.16.10",
|
||||
"@0x/monorepo-scripts": "^3.2.4",
|
||||
"@0xproject/npm-cli-login": "^0.0.11",
|
||||
"async-child-process": "^1.1.1",
|
||||
"coveralls": "^3.0.0",
|
||||
@@ -71,10 +71,11 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "1.19.1",
|
||||
"source-map-support": "^0.5.6",
|
||||
"typescript": "4.2.2",
|
||||
"typescript": "4.6.3",
|
||||
"wsrun": "^5.2.4"
|
||||
},
|
||||
"resolutions": {
|
||||
"merkle-patricia-tree": "3.0.0"
|
||||
"merkle-patricia-tree": "3.0.0",
|
||||
"**/bignumber.js": "^9.0.2"
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,263 @@
|
||||
[
|
||||
{
|
||||
"version": "16.62.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add MDEX on BSC",
|
||||
"pr": 496
|
||||
},
|
||||
{
|
||||
"note": "Add KnightSwap on BSC",
|
||||
"pr": 498
|
||||
},
|
||||
{
|
||||
"note": "Add Velodrome support on Optimism",
|
||||
"pr": 494
|
||||
},
|
||||
{
|
||||
"note": "Do not send empty entries on Quote Report",
|
||||
"pr": 501
|
||||
},
|
||||
{
|
||||
"note": "KnightSwap/Mdex cosmetic change",
|
||||
"pr": 502
|
||||
},
|
||||
{
|
||||
"note": "Offboard JetSwap, CafeSwap, JulSwap, and PolyDex",
|
||||
"pr": 503
|
||||
}
|
||||
],
|
||||
"timestamp": 1655244958
|
||||
},
|
||||
{
|
||||
"version": "16.61.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add stETH wrap/unwrap support",
|
||||
"pr": 476
|
||||
},
|
||||
{
|
||||
"note": "Offboard/clean up Oasis, CoFix, and legacy Kyber",
|
||||
"pr": 482
|
||||
},
|
||||
{
|
||||
"note": "Add MeshSwap on Polygon",
|
||||
"pr": 491
|
||||
}
|
||||
],
|
||||
"timestamp": 1654284040
|
||||
},
|
||||
{
|
||||
"version": "16.60.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Alias Balancer sor to the old version",
|
||||
"pr": 481
|
||||
}
|
||||
],
|
||||
"timestamp": 1652931596
|
||||
},
|
||||
{
|
||||
"version": "16.60.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add BiSwap on BSC",
|
||||
"pr": 467
|
||||
},
|
||||
{
|
||||
"note": "Add GMX and Platypus on Avalanche and Enable KyberDMM on bsc",
|
||||
"pr": 478
|
||||
},
|
||||
{
|
||||
"note": "Add Yoshi Exchange support in Fantom",
|
||||
"pr": 473
|
||||
},
|
||||
{
|
||||
"note": "Fix KyberDMM gas underestimation",
|
||||
"pr": 479
|
||||
}
|
||||
],
|
||||
"timestamp": 1652919697
|
||||
},
|
||||
{
|
||||
"version": "16.59.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Remove SnowSwap on mainnet",
|
||||
"pr": 468
|
||||
},
|
||||
{
|
||||
"note": "Offboard Swerve Finance and LinkSwap",
|
||||
"pr": 469
|
||||
},
|
||||
{
|
||||
"note": "Offboard Eth2Dai",
|
||||
"pr": 470
|
||||
},
|
||||
{
|
||||
"note": "Add an optional IRfqClient for SwapQuoter#getSwapQuoteAsync",
|
||||
"pr": 467
|
||||
}
|
||||
],
|
||||
"timestamp": 1652400434
|
||||
},
|
||||
{
|
||||
"version": "16.58.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update Saddle pools on Mainnet",
|
||||
"pr": 450
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "16.57.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix a runtime error related to BalancerV2SwapInfoCache",
|
||||
"pr": 472
|
||||
}
|
||||
],
|
||||
"timestamp": 1652146864
|
||||
},
|
||||
{
|
||||
"version": "16.57.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix missing AMM quotes on indicative Quote Reports",
|
||||
"pr": 466
|
||||
}
|
||||
],
|
||||
"timestamp": 1651526551
|
||||
},
|
||||
{
|
||||
"version": "16.57.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added QUICK/ANY pair on Polygon",
|
||||
"pr": 464
|
||||
},
|
||||
{
|
||||
"note": "Added cvxFXS/FXS curve pool on mainnet",
|
||||
"pr": 465
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "16.57.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add BalancerV2 batch swap support",
|
||||
"pr": 462
|
||||
}
|
||||
],
|
||||
"timestamp": 1650611093
|
||||
},
|
||||
{
|
||||
"version": "16.56.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add estimatedGas to ExtendedQuoteReport",
|
||||
"pr": 463
|
||||
}
|
||||
],
|
||||
"timestamp": 1650575781
|
||||
},
|
||||
{
|
||||
"version": "16.55.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix fillRfqOrder VIP being used for swaps that need transformERC20",
|
||||
"pr": 461
|
||||
}
|
||||
],
|
||||
"timestamp": 1649347667
|
||||
},
|
||||
{
|
||||
"version": "16.54.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add true VIP support for eligible RFQt swaps",
|
||||
"pr": 458
|
||||
}
|
||||
],
|
||||
"timestamp": 1649215576
|
||||
},
|
||||
{
|
||||
"version": "16.53.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Adds support for STG/USDC pool on Curve Mainnet",
|
||||
"pr": 451
|
||||
},
|
||||
{
|
||||
"note": "Use neon-router in asset-swapper tests",
|
||||
"pr": 453
|
||||
},
|
||||
{
|
||||
"note": "Add sampler blocknumber to quote report data",
|
||||
"pr": 448
|
||||
}
|
||||
],
|
||||
"timestamp": 1648739346
|
||||
},
|
||||
{
|
||||
"version": "16.52.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Adds support for mobius money on celo",
|
||||
"pr": 423
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "16.51.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added `Curve` `YFI-ETH` pool",
|
||||
"pr": 444
|
||||
}
|
||||
],
|
||||
"timestamp": 1646888282
|
||||
},
|
||||
{
|
||||
"version": "16.50.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Routing glue optimization",
|
||||
"pr": 439
|
||||
},
|
||||
{
|
||||
"note": "Move VIP source routing into neon-router & disable fallback orders for native/plp",
|
||||
"pr": 440
|
||||
}
|
||||
],
|
||||
"timestamp": 1646837959
|
||||
},
|
||||
{
|
||||
"version": "16.50.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update `Uniswap_V3` address on `Ropsten`",
|
||||
"pr": 441
|
||||
}
|
||||
],
|
||||
"timestamp": 1646617024
|
||||
},
|
||||
{
|
||||
"version": "16.50.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add BTRFLY/WETH Curve pool on mainnet",
|
||||
"pr": 437
|
||||
},
|
||||
{
|
||||
"note": "Lower Uniswap V3 Sampler gas allowance",
|
||||
"pr": 438
|
||||
}
|
||||
],
|
||||
"timestamp": 1646312638
|
||||
},
|
||||
{
|
||||
"version": "16.50.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,100 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v16.62.0 - _June 14, 2022_
|
||||
|
||||
* Add MDEX on BSC (#496)
|
||||
* Add KnightSwap on BSC (#498)
|
||||
* Add Velodrome support on Optimism (#494)
|
||||
* Do not send empty entries on Quote Report (#501)
|
||||
* KnightSwap/Mdex cosmetic change (#502)
|
||||
* Offboard JetSwap, CafeSwap, JulSwap, and PolyDex (#503)
|
||||
|
||||
## v16.61.0 - _June 3, 2022_
|
||||
|
||||
* Add stETH wrap/unwrap support (#476)
|
||||
* Offboard/clean up Oasis, CoFix, and legacy Kyber (#482)
|
||||
* Add MeshSwap on Polygon (#491)
|
||||
|
||||
## v16.60.1 - _May 19, 2022_
|
||||
|
||||
* Alias Balancer sor to the old version (#481)
|
||||
|
||||
## v16.60.0 - _May 19, 2022_
|
||||
|
||||
* Add BiSwap on BSC (#467)
|
||||
* Add GMX and Platypus on Avalanche and Enable KyberDMM on bsc (#478)
|
||||
* Add Yoshi Exchange support in Fantom (#473)
|
||||
* Fix KyberDMM gas underestimation (#479)
|
||||
|
||||
## v16.59.0 - _May 13, 2022_
|
||||
|
||||
* Remove SnowSwap on mainnet (#468)
|
||||
* Offboard Swerve Finance and LinkSwap (#469)
|
||||
* Offboard Eth2Dai (#470)
|
||||
* Add an optional IRfqClient for SwapQuoter#getSwapQuoteAsync (#467)
|
||||
|
||||
## v16.58.0 - _Invalid date_
|
||||
|
||||
* Update Saddle pools on Mainnet (#450)
|
||||
|
||||
## v16.57.3 - _May 10, 2022_
|
||||
|
||||
* Fix a runtime error related to BalancerV2SwapInfoCache (#472)
|
||||
|
||||
## v16.57.2 - _May 2, 2022_
|
||||
|
||||
* Fix missing AMM quotes on indicative Quote Reports (#466)
|
||||
|
||||
## v16.57.1 - _Invalid date_
|
||||
|
||||
* Added QUICK/ANY pair on Polygon (#464)
|
||||
* Added cvxFXS/FXS curve pool on mainnet (#465)
|
||||
|
||||
## v16.57.0 - _April 22, 2022_
|
||||
|
||||
* Add BalancerV2 batch swap support (#462)
|
||||
|
||||
## v16.56.0 - _April 21, 2022_
|
||||
|
||||
* Add estimatedGas to ExtendedQuoteReport (#463)
|
||||
|
||||
## v16.55.0 - _April 7, 2022_
|
||||
|
||||
* Fix fillRfqOrder VIP being used for swaps that need transformERC20 (#461)
|
||||
|
||||
## v16.54.0 - _April 6, 2022_
|
||||
|
||||
* Add true VIP support for eligible RFQt swaps (#458)
|
||||
|
||||
## v16.53.0 - _March 31, 2022_
|
||||
|
||||
* Adds support for STG/USDC pool on Curve Mainnet (#451)
|
||||
* Use neon-router in asset-swapper tests (#453)
|
||||
* Add sampler blocknumber to quote report data (#448)
|
||||
|
||||
## v16.52.0 - _Invalid date_
|
||||
|
||||
* Adds support for mobius money on celo (#423)
|
||||
|
||||
## v16.51.0 - _March 10, 2022_
|
||||
|
||||
* Added `Curve` `YFI-ETH` pool (#444)
|
||||
|
||||
## v16.50.3 - _March 9, 2022_
|
||||
|
||||
* Routing glue optimization (#439)
|
||||
* Move VIP source routing into neon-router & disable fallback orders for native/plp (#440)
|
||||
|
||||
## v16.50.2 - _March 7, 2022_
|
||||
|
||||
* Update `Uniswap_V3` address on `Ropsten` (#441)
|
||||
|
||||
## v16.50.1 - _March 3, 2022_
|
||||
|
||||
* Add BTRFLY/WETH Curve pool on mainnet (#437)
|
||||
* Lower Uniswap V3 Sampler gas allowance (#438)
|
||||
|
||||
## v16.50.0 - _March 2, 2022_
|
||||
|
||||
* Adding support for Geist on `Fantom` (#398)
|
||||
|
@@ -6,7 +6,7 @@
|
||||
"shouldSaveStandardInput": true,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": { "enabled": true, "runs": 200, "details": { "yul": true, "deduplicate": true } },
|
||||
"optimizer": { "enabled": true, "runs": 200, "details": { "yul": false, "deduplicate": true } },
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
|
105
packages/asset-swapper/contracts/src/BalancerV2BatchSampler.sol
Normal file
105
packages/asset-swapper/contracts/src/BalancerV2BatchSampler.sol
Normal file
@@ -0,0 +1,105 @@
|
||||
// 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 "./interfaces/IBalancerV2Vault.sol";
|
||||
import "./BalancerV2Common.sol";
|
||||
|
||||
contract BalancerV2BatchSampler is BalancerV2Common {
|
||||
|
||||
// Replaces amount for first step with each takerTokenAmount and calls queryBatchSwap using supplied steps
|
||||
/// @dev Sample sell quotes from Balancer V2 supporting multihops.
|
||||
/// @param swapSteps Array of swap steps (can be >= 1).
|
||||
/// @param swapAssets Array of token address for swaps.
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
function sampleMultihopSellsFromBalancerV2(
|
||||
IBalancerV2Vault vault,
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps,
|
||||
address[] memory swapAssets,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||
_createSwapFunds();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
swapSteps[0].amount = 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
|
||||
// Note - queryBatchSwap will return a delta for each token in the assets array and last asset should be tokenOut
|
||||
int256 amountOutFromPool = amounts[amounts.length - 1] * -1;
|
||||
if (amountOutFromPool <= 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = uint256(amountOutFromPool);
|
||||
} catch {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces amount for first step with each makerTokenAmount and calls queryBatchSwap using supplied steps
|
||||
/// @dev Sample buy quotes from Balancer V2 supporting multihops.
|
||||
/// @param swapSteps Array of swap steps (can be >= 1).
|
||||
/// @param swapAssets Array of token address for swaps.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
function sampleMultihopBuysFromBalancerV2(
|
||||
IBalancerV2Vault vault,
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps,
|
||||
address[] memory swapAssets,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||
_createSwapFunds();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
swapSteps[0].amount = makerTokenAmounts[i];
|
||||
try
|
||||
// Uses GIVEN_OUT type for Buy
|
||||
vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_OUT, swapSteps, swapAssets, swapFunds)
|
||||
// amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
|
||||
returns (int256[] memory amounts) {
|
||||
int256 amountIntoPool = amounts[0];
|
||||
if (amountIntoPool <= 0) {
|
||||
break;
|
||||
}
|
||||
takerTokenAmounts[i] = uint256(amountIntoPool);
|
||||
} catch {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
packages/asset-swapper/contracts/src/BalancerV2Common.sol
Normal file
41
packages/asset-swapper/contracts/src/BalancerV2Common.sol
Normal file
@@ -0,0 +1,41 @@
|
||||
// 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 "./interfaces/IBalancerV2Vault.sol";
|
||||
|
||||
|
||||
contract BalancerV2Common {
|
||||
|
||||
function _createSwapFunds()
|
||||
internal
|
||||
view
|
||||
returns (IBalancerV2Vault.FundManagement memory)
|
||||
{
|
||||
return
|
||||
IBalancerV2Vault.FundManagement({
|
||||
sender: address(this),
|
||||
fromInternalBalance: false,
|
||||
recipient: payable(address(this)),
|
||||
toInternalBalance: false
|
||||
});
|
||||
}
|
||||
}
|
@@ -21,44 +21,11 @@ pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./SamplerUtils.sol";
|
||||
import "./interfaces/IBalancerV2Vault.sol";
|
||||
import "./BalancerV2Common.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;
|
||||
}
|
||||
contract BalancerV2Sampler is SamplerUtils, BalancerV2Common {
|
||||
|
||||
/// @dev Sample sell quotes from Balancer V2.
|
||||
/// @param poolInfo Struct with pool related data
|
||||
@@ -68,7 +35,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromBalancerV2(
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
IBalancerV2Vault.BalancerV2PoolInfo memory poolInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
@@ -78,9 +45,9 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||
IAsset[] memory swapAssets = new IAsset[](2);
|
||||
swapAssets[0] = IAsset(takerToken);
|
||||
swapAssets[1] = IAsset(makerToken);
|
||||
address[] memory swapAssets = new address[](2);
|
||||
swapAssets[0] = takerToken;
|
||||
swapAssets[1] = makerToken;
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
@@ -97,7 +64,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
// 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;
|
||||
int256 amountOutFromPool = amounts[amounts.length - 1] * -1;
|
||||
if (amountOutFromPool <= 0) {
|
||||
break;
|
||||
}
|
||||
@@ -117,7 +84,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromBalancerV2(
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
IBalancerV2Vault.BalancerV2PoolInfo memory poolInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
@@ -127,9 +94,9 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||
IAsset[] memory swapAssets = new IAsset[](2);
|
||||
swapAssets[0] = IAsset(takerToken);
|
||||
swapAssets[1] = IAsset(makerToken);
|
||||
address[] memory swapAssets = new address[](2);
|
||||
swapAssets[0] = takerToken;
|
||||
swapAssets[1] = makerToken;
|
||||
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
@@ -157,7 +124,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
}
|
||||
|
||||
function _createSwapSteps(
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
IBalancerV2Vault.BalancerV2PoolInfo memory poolInfo,
|
||||
uint256 amount
|
||||
) private pure returns (IBalancerV2Vault.BatchSwapStep[] memory) {
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||
@@ -172,18 +139,4 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
|
||||
return swapSteps;
|
||||
}
|
||||
|
||||
function _createSwapFunds()
|
||||
private
|
||||
view
|
||||
returns (IBalancerV2Vault.FundManagement memory)
|
||||
{
|
||||
return
|
||||
IBalancerV2Vault.FundManagement({
|
||||
sender: address(this),
|
||||
fromInternalBalance: false,
|
||||
recipient: payable(address(this)),
|
||||
toInternalBalance: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -22,9 +22,8 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IBancor.sol";
|
||||
|
||||
contract CompilerHack {}
|
||||
|
||||
contract BancorSampler is CompilerHack {
|
||||
contract BancorSampler {
|
||||
|
||||
/// @dev Base gas limit for Bancor calls.
|
||||
uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k
|
||||
|
120
packages/asset-swapper/contracts/src/BancorV3Sampler.sol
Normal file
120
packages/asset-swapper/contracts/src/BancorV3Sampler.sol
Normal file
@@ -0,0 +1,120 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 "./interfaces/IBancorV3.sol";
|
||||
|
||||
|
||||
contract BancorV3Sampler
|
||||
{
|
||||
/// @dev Gas limit for BancorV3 calls.
|
||||
uint256 constant private BancorV3_CALL_GAS = 150e3; // 150k
|
||||
|
||||
address constant public ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
|
||||
/// @dev Sample sell quotes from BancorV3.
|
||||
/// @param weth The WETH contract address
|
||||
/// @param router Router to look up tokens and amounts
|
||||
/// @param path Token route. Should be takerToken -> makerToken
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromBancorV3(
|
||||
address weth,
|
||||
address router,
|
||||
address[] memory path,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
if(path[0] == weth){
|
||||
path[0] = ETH;
|
||||
}
|
||||
if(path[1] == weth){
|
||||
path[1] = ETH;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IBancorV3(router).tradeOutputBySourceAmount(path[0], path[1], takerTokenAmounts[i])
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from BancorV3.
|
||||
/// @param weth The WETH contract address
|
||||
/// @param router Router to look up tokens and amounts
|
||||
/// @param path Token route. Should be takerToken -> makerToken.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromBancorV3(
|
||||
address weth,
|
||||
address router,
|
||||
address[] memory path,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
if(path[0] == weth){
|
||||
path[0] = ETH;
|
||||
}
|
||||
if(path[1] == weth){
|
||||
path[1] = ETH;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IBancorV3(router).tradeInputByTargetAmount(path[0], path[1], makerTokenAmounts[i])
|
||||
returns (uint256 amount)
|
||||
{
|
||||
takerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (takerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,52 +22,58 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./BalancerSampler.sol";
|
||||
import "./BalancerV2Sampler.sol";
|
||||
import "./BalancerV2BatchSampler.sol";
|
||||
import "./BancorSampler.sol";
|
||||
import "./BancorV3Sampler.sol";
|
||||
import "./CompoundSampler.sol";
|
||||
import "./CurveSampler.sol";
|
||||
import "./DODOSampler.sol";
|
||||
import "./DODOV2Sampler.sol";
|
||||
import "./KyberSampler.sol";
|
||||
import "./GMXSampler.sol";
|
||||
import "./KyberDmmSampler.sol";
|
||||
import "./LidoSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
import "./MakerPSMSampler.sol";
|
||||
import "./MultiBridgeSampler.sol";
|
||||
import "./MStableSampler.sol";
|
||||
import "./MooniswapSampler.sol";
|
||||
import "./NativeOrderSampler.sol";
|
||||
import "./PlatypusSampler.sol";
|
||||
import "./ShellSampler.sol";
|
||||
import "./SmoothySampler.sol";
|
||||
import "./TwoHopSampler.sol";
|
||||
import "./UniswapSampler.sol";
|
||||
import "./UniswapV2Sampler.sol";
|
||||
import "./UniswapV3Sampler.sol";
|
||||
import "./VelodromeSampler.sol";
|
||||
import "./UtilitySampler.sol";
|
||||
|
||||
|
||||
contract ERC20BridgeSampler is
|
||||
BalancerSampler,
|
||||
BalancerV2Sampler,
|
||||
BalancerV2BatchSampler,
|
||||
BancorSampler,
|
||||
BancorV3Sampler,
|
||||
CompoundSampler,
|
||||
CurveSampler,
|
||||
DODOSampler,
|
||||
DODOV2Sampler,
|
||||
KyberSampler,
|
||||
GMXSampler,
|
||||
KyberDmmSampler,
|
||||
LidoSampler,
|
||||
LiquidityProviderSampler,
|
||||
MakerPSMSampler,
|
||||
MStableSampler,
|
||||
MooniswapSampler,
|
||||
MultiBridgeSampler,
|
||||
NativeOrderSampler,
|
||||
PlatypusSampler,
|
||||
ShellSampler,
|
||||
SmoothySampler,
|
||||
TwoHopSampler,
|
||||
UniswapSampler,
|
||||
UniswapV2Sampler,
|
||||
UniswapV3Sampler,
|
||||
VelodromeSampler,
|
||||
UtilitySampler
|
||||
{
|
||||
|
||||
@@ -92,4 +98,6 @@ contract ERC20BridgeSampler is
|
||||
(callResults[i].success, callResults[i].data) = address(this).call(callDatas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
}
|
||||
|
96
packages/asset-swapper/contracts/src/GMXSampler.sol
Normal file
96
packages/asset-swapper/contracts/src/GMXSampler.sol
Normal file
@@ -0,0 +1,96 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IGMX.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
contract GMXSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
struct GMXInfo {
|
||||
address reader;
|
||||
address vault;
|
||||
address[] path;
|
||||
}
|
||||
|
||||
function sampleSellsFromGMX(
|
||||
address reader,
|
||||
address vault,
|
||||
address[] memory path,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IGMX(reader).getAmountOut(IVault(vault), path[0], path[1], takerTokenAmounts[i])
|
||||
returns (uint256 amountAfterFees, uint256 feeAmount)
|
||||
{
|
||||
makerTokenAmounts[i] = amountAfterFees;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sampleBuysFromGMX(
|
||||
address reader,
|
||||
address vault,
|
||||
address[] memory path,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
address[] memory invertBuyPath = new address[](2);
|
||||
invertBuyPath[0] = path[1];
|
||||
invertBuyPath[1] = path[0];
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(reader, vault, invertBuyPath),
|
||||
takerTokenData: abi.encode(reader, vault, path),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromGMX
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function _sampleSellForApproximateBuyFromGMX(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(address _reader, address _vault, address[] memory _path ) = abi.decode(takerTokenData, (address, address, address[]));
|
||||
|
||||
(bool success, bytes memory resultData) = address(this).staticcall(abi.encodeWithSelector(
|
||||
this.sampleSellsFromGMX.selector,
|
||||
_reader,
|
||||
_vault,
|
||||
_path,
|
||||
_toSingleValueArray(sellAmount)
|
||||
));
|
||||
if(!success) {
|
||||
return 0;
|
||||
}
|
||||
// solhint-disable-next-line indent
|
||||
return abi.decode(resultData, (uint256[]))[0];
|
||||
}
|
||||
|
||||
}
|
@@ -1,301 +0,0 @@
|
||||
// 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IKyberNetwork.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract KyberSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
/// @dev Gas limit for Kyber calls.
|
||||
uint256 constant private KYBER_CALL_GAS = 500e3; // 500k
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
|
||||
struct KyberSamplerOpts {
|
||||
uint256 reserveOffset;
|
||||
address hintHandler;
|
||||
address networkProxy;
|
||||
address weth;
|
||||
bytes hint;
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Kyber.
|
||||
/// @param opts KyberSamplerOpts The nth reserve
|
||||
/// @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 reserveId The id of the reserve found at reserveOffset
|
||||
/// @return hint The hint for the selected reserve
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token amount.
|
||||
function sampleSellsFromKyberNetwork(
|
||||
KyberSamplerOpts memory opts,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bytes32 reserveId, bytes memory hint, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
reserveId = _getNextReserveId(opts, takerToken, makerToken);
|
||||
if (reserveId == 0x0) {
|
||||
return (reserveId, hint, makerTokenAmounts);
|
||||
}
|
||||
opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
|
||||
hint = opts.hint;
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 value = this.sampleSellFromKyberNetwork(
|
||||
opts,
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
makerTokenAmounts[i] = value;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Kyber.
|
||||
/// @param opts KyberSamplerOpts The nth reserve
|
||||
/// @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 reserveId The id of the reserve found at reserveOffset
|
||||
/// @return hint The hint for the selected reserve
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token amount.
|
||||
function sampleBuysFromKyberNetwork(
|
||||
KyberSamplerOpts memory opts,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bytes32 reserveId, bytes memory hint, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
reserveId = _getNextReserveId(opts, takerToken, makerToken);
|
||||
if (reserveId == 0x0) {
|
||||
return (reserveId, hint, takerTokenAmounts);
|
||||
}
|
||||
opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
|
||||
hint = opts.hint;
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, opts),
|
||||
takerTokenData: abi.encode(takerToken, opts),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromKyber
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
return (reserveId, hint, takerTokenAmounts);
|
||||
}
|
||||
|
||||
function encodeKyberHint(
|
||||
KyberSamplerOpts memory opts,
|
||||
bytes32 reserveId,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bytes memory hint)
|
||||
{
|
||||
// Build a hint selecting the single reserve
|
||||
IKyberHintHandler kyberHint = IKyberHintHandler(opts.hintHandler);
|
||||
|
||||
// All other reserves should be ignored with this hint
|
||||
bytes32[] memory selectedReserves = new bytes32[](1);
|
||||
selectedReserves[0] = reserveId;
|
||||
uint256[] memory emptySplits = new uint256[](0);
|
||||
|
||||
if (takerToken == opts.weth) {
|
||||
// ETH to Token
|
||||
try
|
||||
kyberHint.buildEthToTokenHint
|
||||
{gas: KYBER_CALL_GAS}
|
||||
(
|
||||
makerToken,
|
||||
IKyberHintHandler.TradeType.MaskIn,
|
||||
selectedReserves,
|
||||
emptySplits
|
||||
)
|
||||
returns (bytes memory result)
|
||||
{
|
||||
return result;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
}
|
||||
} else if (makerToken == opts.weth) {
|
||||
// Token to ETH
|
||||
try
|
||||
kyberHint.buildTokenToEthHint
|
||||
{gas: KYBER_CALL_GAS}
|
||||
(
|
||||
takerToken,
|
||||
IKyberHintHandler.TradeType.MaskIn,
|
||||
selectedReserves,
|
||||
emptySplits
|
||||
)
|
||||
returns (bytes memory result)
|
||||
{
|
||||
return result;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
}
|
||||
|
||||
} else {
|
||||
// Token to Token
|
||||
// We use the same reserve both ways
|
||||
try
|
||||
kyberHint.buildTokenToTokenHint
|
||||
{gas: KYBER_CALL_GAS}
|
||||
(
|
||||
takerToken,
|
||||
IKyberHintHandler.TradeType.MaskIn,
|
||||
selectedReserves,
|
||||
emptySplits,
|
||||
makerToken,
|
||||
IKyberHintHandler.TradeType.MaskIn,
|
||||
selectedReserves,
|
||||
emptySplits
|
||||
)
|
||||
returns (bytes memory result)
|
||||
{
|
||||
return result;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromKyber(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(address makerToken, KyberSamplerOpts memory opts) =
|
||||
abi.decode(makerTokenData, (address, KyberSamplerOpts));
|
||||
(address takerToken, ) =
|
||||
abi.decode(takerTokenData, (address, KyberSamplerOpts));
|
||||
try
|
||||
this.sampleSellFromKyberNetwork
|
||||
(opts, takerToken, makerToken, sellAmount)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
return amount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function sampleSellFromKyberNetwork(
|
||||
KyberSamplerOpts memory opts,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256 makerTokenAmount)
|
||||
{
|
||||
// If there is no hint do not continue
|
||||
if (opts.hint.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try
|
||||
IKyberNetworkProxy(opts.networkProxy).getExpectedRateAfterFee
|
||||
{gas: KYBER_CALL_GAS}
|
||||
(
|
||||
takerToken == opts.weth ? KYBER_ETH_ADDRESS : takerToken,
|
||||
makerToken == opts.weth ? KYBER_ETH_ADDRESS : makerToken,
|
||||
takerTokenAmount,
|
||||
0, // fee
|
||||
opts.hint
|
||||
)
|
||||
returns (uint256 rate)
|
||||
{
|
||||
uint256 makerTokenDecimals = _getTokenDecimals(makerToken);
|
||||
uint256 takerTokenDecimals = _getTokenDecimals(takerToken);
|
||||
makerTokenAmount =
|
||||
rate *
|
||||
takerTokenAmount *
|
||||
10 ** makerTokenDecimals /
|
||||
10 ** takerTokenDecimals /
|
||||
10 ** 18;
|
||||
return makerTokenAmount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function _getNextReserveId(
|
||||
KyberSamplerOpts memory opts,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bytes32 reserveId)
|
||||
{
|
||||
// Fetch the registered reserves for this pair
|
||||
IKyberHintHandler kyberHint = IKyberHintHandler(opts.hintHandler);
|
||||
(bytes32[] memory reserveIds, ,) = kyberHint.getTradingReserves(
|
||||
takerToken == opts.weth ? KYBER_ETH_ADDRESS : takerToken,
|
||||
makerToken == opts.weth ? KYBER_ETH_ADDRESS : makerToken,
|
||||
true,
|
||||
new bytes(0) // empty hint
|
||||
);
|
||||
|
||||
if (opts.reserveOffset >= reserveIds.length) {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
reserveId = reserveIds[opts.reserveOffset];
|
||||
// Ignore Kyber Bridged Reserves (0xbb)
|
||||
if (uint256(reserveId >> 248) == 0xbb) {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
return reserveId;
|
||||
}
|
||||
}
|
@@ -22,10 +22,18 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
interface IWstETH {
|
||||
function getWstETHByStETH(uint256 _stETHAmount) external view returns (uint256);
|
||||
function getStETHByWstETH(uint256 _wstETHAmount) external view returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract LidoSampler is SamplerUtils {
|
||||
struct LidoInfo {
|
||||
address stEthToken;
|
||||
address wethToken;
|
||||
address wstEthToken;
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Lido
|
||||
@@ -42,20 +50,17 @@ contract LidoSampler is SamplerUtils {
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
pure
|
||||
view
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
if (takerToken != lidoInfo.wethToken || makerToken != address(lidoInfo.stEthToken)) {
|
||||
// Return 0 values if not selling WETH for stETH
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
uint256[] memory makerTokenAmounts = new uint256[](numSamples);
|
||||
return makerTokenAmounts;
|
||||
if (takerToken == lidoInfo.wethToken && makerToken == address(lidoInfo.stEthToken)) {
|
||||
// Minting stETH is always 1:1 therefore we can just return the same amounts back.
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
// Minting stETH is always 1:1 therefore we can just return the same amounts back
|
||||
return takerTokenAmounts;
|
||||
return _sampleSellsForWrapped(lidoInfo, takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Lido.
|
||||
@@ -72,20 +77,43 @@ contract LidoSampler is SamplerUtils {
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
pure
|
||||
view
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
if (takerToken != lidoInfo.wethToken || makerToken != address(lidoInfo.stEthToken)) {
|
||||
// Return 0 values if not buying stETH for WETH
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
uint256[] memory takerTokenAmounts = new uint256[](numSamples);
|
||||
return takerTokenAmounts;
|
||||
if (takerToken == lidoInfo.wethToken && makerToken == address(lidoInfo.stEthToken)) {
|
||||
// Minting stETH is always 1:1 therefore we can just return the same amounts back.
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
// Minting stETH is always 1:1 therefore we can just return the same amounts back
|
||||
return makerTokenAmounts;
|
||||
// Swap out `makerToken` and `takerToken` and re-use `_sampleSellsForWrapped`.
|
||||
return _sampleSellsForWrapped(lidoInfo, makerToken, takerToken, makerTokenAmounts);
|
||||
}
|
||||
|
||||
function _sampleSellsForWrapped(
|
||||
LidoInfo memory lidoInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
) private view returns (uint256[] memory) {
|
||||
IWstETH wstETH = IWstETH(lidoInfo.wstEthToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
uint256[] memory makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
if (takerToken == lidoInfo.stEthToken && makerToken == lidoInfo.wstEthToken) {
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
makerTokenAmounts[i] = wstETH.getWstETHByStETH(takerTokenAmounts[i]);
|
||||
}
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
if (takerToken == lidoInfo.wstEthToken && makerToken == lidoInfo.stEthToken) {
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
makerTokenAmounts[i] = wstETH.getStETHByWstETH(takerTokenAmounts[i]);
|
||||
}
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
// Returns 0 values.
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
}
|
||||
|
@@ -1,82 +0,0 @@
|
||||
// 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IMultiBridge.sol";
|
||||
|
||||
|
||||
contract MultiBridgeSampler {
|
||||
|
||||
/// @dev Default gas limit for multibridge calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
||||
|
||||
/// @dev Sample sell quotes from MultiBridge.
|
||||
/// @param multibridge Address of the MultiBridge contract.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param intermediateToken The address of the intermediate token to
|
||||
/// use in an indirect route.
|
||||
/// @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 sampleSellsFromMultiBridge(
|
||||
address multibridge,
|
||||
address takerToken,
|
||||
address intermediateToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// If no address provided, return all zeros.
|
||||
if (multibridge == address(0)) {
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
multibridge.staticcall.gas(DEFAULT_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IMultiBridge(0).getSellQuote.selector,
|
||||
takerToken,
|
||||
intermediateToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
// Exit early if the amount is too high for the source to serve
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
}
|
89
packages/asset-swapper/contracts/src/PlatypusSampler.sol
Normal file
89
packages/asset-swapper/contracts/src/PlatypusSampler.sol
Normal file
@@ -0,0 +1,89 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IPlatypus.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract PlatypusSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
function sampleSellsFromPlatypus(
|
||||
address pool,
|
||||
address[] memory path,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IPlatypus(pool).quotePotentialSwap(path[0], path[1], takerTokenAmounts[i])
|
||||
returns (uint256 amountAfterFees, uint256 feeAmount)
|
||||
{
|
||||
makerTokenAmounts[i] = amountAfterFees;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory result) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sampleBuysFromPlatypus(
|
||||
address pool,
|
||||
address[] memory path,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
address[] memory invertBuyPath = new address[](2);
|
||||
invertBuyPath[0] = path[1];
|
||||
invertBuyPath[1] = path[0];
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(pool, invertBuyPath),
|
||||
takerTokenData: abi.encode(pool, path),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromPlatypus
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function _sampleSellForApproximateBuyFromPlatypus(
|
||||
bytes memory makerTokenData,
|
||||
bytes memory takerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(address _pool, address[] memory _path ) = abi.decode(makerTokenData, (address, address[]));
|
||||
|
||||
(bool success, bytes memory resultData) = address(this).staticcall(abi.encodeWithSelector(
|
||||
this.sampleSellsFromPlatypus.selector,
|
||||
_pool,
|
||||
_path,
|
||||
_toSingleValueArray(sellAmount)
|
||||
));
|
||||
if(!success) {
|
||||
return 0;
|
||||
}
|
||||
// solhint-disable-next-line indent
|
||||
return abi.decode(resultData, (uint256[]))[0];
|
||||
}
|
||||
}
|
@@ -77,7 +77,7 @@ interface IUniswapV3Pool {
|
||||
contract UniswapV3Sampler
|
||||
{
|
||||
/// @dev Gas limit for UniswapV3 calls. This is 100% a guess.
|
||||
uint256 constant private QUOTE_GAS = 900e3;
|
||||
uint256 constant private QUOTE_GAS = 700e3;
|
||||
|
||||
/// @dev Sample sell quotes from UniswapV3.
|
||||
/// @param quoter UniswapV3 Quoter contract.
|
||||
|
134
packages/asset-swapper/contracts/src/VelodromeSampler.sol
Normal file
134
packages/asset-swapper/contracts/src/VelodromeSampler.sol
Normal file
@@ -0,0 +1,134 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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 './ApproximateBuys.sol';
|
||||
import './SamplerUtils.sol';
|
||||
|
||||
struct VeloRoute {
|
||||
address from;
|
||||
address to;
|
||||
bool stable;
|
||||
}
|
||||
|
||||
interface IVelodromeRouter {
|
||||
function getAmountOut(
|
||||
uint256 amountIn,
|
||||
address tokenIn,
|
||||
address tokenOut
|
||||
) external view returns (uint256 amount, bool stable);
|
||||
|
||||
function getAmountsOut(uint256 amountIn, VeloRoute[] calldata routes)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory amounts);
|
||||
}
|
||||
|
||||
contract VelodromeSampler is SamplerUtils, ApproximateBuys {
|
||||
/// @dev Sample sell quotes from Velodrome
|
||||
/// @param router Address of Velodrome router.
|
||||
/// @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 (sorted in ascending order).
|
||||
/// @return stable Whether the pool is a stable pool (vs volatile).
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token amount.
|
||||
function sampleSellsFromVelodrome(
|
||||
IVelodromeRouter router,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
) public view returns (bool stable, uint256[] memory makerTokenAmounts) {
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// Sampling should not mix stable and volatile pools.
|
||||
// Find the most liquid pool based on max(takerTokenAmounts) and stick with it.
|
||||
stable = _isMostLiquidPoolStablePool(router, takerToken, makerToken, takerTokenAmounts);
|
||||
VeloRoute[] memory routes = new VeloRoute[](1);
|
||||
routes[0] = VeloRoute({ from: takerToken, to: makerToken, stable: stable });
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
makerTokenAmounts[i] = router.getAmountsOut(takerTokenAmounts[i], routes)[1];
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Velodrome.
|
||||
/// @param router Address of Velodrome router.
|
||||
/// @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 stable Whether the pool is a stable pool (vs volatile).
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token amount.
|
||||
function sampleBuysFromVelodrome(
|
||||
IVelodromeRouter router,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
) public view returns (bool stable, uint256[] memory takerTokenAmounts) {
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
// Sampling should not mix stable and volatile pools.
|
||||
// Find the most liquid pool based on the reverse swap (maker -> taker) and stick with it.
|
||||
stable = _isMostLiquidPoolStablePool(router, makerToken, takerToken, makerTokenAmounts);
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
takerTokenData: abi.encode(router, VeloRoute({ from: takerToken, to: makerToken, stable: stable })),
|
||||
makerTokenData: abi.encode(router, VeloRoute({ from: makerToken, to: takerToken, stable: stable })),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromVelodrome
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromVelodrome(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory, /* makerTokenData */
|
||||
uint256 sellAmount
|
||||
) internal view returns (uint256) {
|
||||
(IVelodromeRouter router, VeloRoute memory route) = abi.decode(takerTokenData, (IVelodromeRouter, VeloRoute));
|
||||
|
||||
VeloRoute[] memory routes = new VeloRoute[](1);
|
||||
routes[0] = route;
|
||||
return router.getAmountsOut(sellAmount, routes)[1];
|
||||
}
|
||||
|
||||
/// @dev Returns whether the most liquid pool is a stable pool.
|
||||
/// @param router Address of Velodrome router.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token buy amount for each sample (sorted in ascending order)
|
||||
/// @return stable Whether the pool is a stable pool (vs volatile).
|
||||
function _isMostLiquidPoolStablePool(
|
||||
IVelodromeRouter router,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
) internal view returns (bool stable) {
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
(, stable) = router.getAmountOut(takerTokenAmounts[numSamples - 1], takerToken, makerToken);
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
// 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
/// @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;
|
||||
}
|
||||
|
||||
struct BalancerV2PoolInfo {
|
||||
bytes32 poolId;
|
||||
address vault;
|
||||
}
|
||||
|
||||
function queryBatchSwap(
|
||||
SwapKind kind,
|
||||
BatchSwapStep[] calldata swaps,
|
||||
address[] calldata assets,
|
||||
FundManagement calldata funds
|
||||
) external returns (int256[] memory assetDeltas);
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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;
|
||||
|
||||
interface IBancorV3 {
|
||||
|
||||
/**
|
||||
* @dev returns the output amount when trading by providing the source amount
|
||||
*/
|
||||
function tradeOutputBySourceAmount(
|
||||
address sourceToken,
|
||||
address targetToken,
|
||||
uint256 sourceAmount
|
||||
) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev returns the input amount when trading by providing the target amount
|
||||
*/
|
||||
function tradeInputByTargetAmount(
|
||||
address sourceToken,
|
||||
address targetToken,
|
||||
uint256 targetAmount
|
||||
) external view returns (uint256);
|
||||
|
||||
}
|
23
packages/asset-swapper/contracts/src/interfaces/IGMX.sol
Normal file
23
packages/asset-swapper/contracts/src/interfaces/IGMX.sol
Normal file
@@ -0,0 +1,23 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface IGMX {
|
||||
function getMaxAmountIn(IVault _vault, address _tokenIn, address _tokenOut)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
function getAmountOut(IVault _vault, address _tokenIn, address _tokenOut, uint256 _amountIn)
|
||||
external
|
||||
view
|
||||
returns (uint256, uint256);
|
||||
}
|
||||
|
||||
interface IVault {
|
||||
function getFeeBasisPoints(address _token, uint256 _usdgDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256);
|
||||
function stableSwapFeeBasisPoints() external view returns (uint256);
|
||||
function stableTokens(address _token) external view returns (bool);
|
||||
function tokenDecimals(address _token) external view returns (uint256);
|
||||
function getMaxPrice(address _token) external view returns (uint256);
|
||||
function getMinPrice(address _token) external view returns (uint256);
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
// 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;
|
||||
|
||||
// Keepin everything together
|
||||
interface IKyberNetwork {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
interface IKyberNetworkProxy {
|
||||
|
||||
function getExpectedRateAfterFee(
|
||||
address src,
|
||||
address dest,
|
||||
uint256 srcQty,
|
||||
uint256 platformFeeBps,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256 expectedRate);
|
||||
}
|
||||
|
||||
interface IKyberHintHandler {
|
||||
|
||||
enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
|
||||
|
||||
enum ProcessWithRate {NotRequired, Required}
|
||||
|
||||
function getTradingReserves(
|
||||
address tokenSrc,
|
||||
address tokenDest,
|
||||
bool isTokenToToken,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
bytes32[] memory reserveIds,
|
||||
uint256[] memory splitValuesBps,
|
||||
ProcessWithRate processWithRate
|
||||
);
|
||||
|
||||
function buildTokenToEthHint(
|
||||
address tokenSrc,
|
||||
TradeType tokenToEthType,
|
||||
bytes32[] calldata tokenToEthReserveIds,
|
||||
uint256[] calldata tokenToEthSplits
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes memory hint);
|
||||
|
||||
function buildEthToTokenHint(
|
||||
address tokenDest,
|
||||
TradeType ethToTokenType,
|
||||
bytes32[] calldata ethToTokenReserveIds,
|
||||
uint256[] calldata ethToTokenSplits
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes memory hint);
|
||||
|
||||
function buildTokenToTokenHint(
|
||||
address tokenSrc,
|
||||
TradeType tokenToEthType,
|
||||
bytes32[] calldata tokenToEthReserveIds,
|
||||
uint256[] calldata tokenToEthSplits,
|
||||
address tokenDest,
|
||||
TradeType ethToTokenType,
|
||||
bytes32[] calldata ethToTokenReserveIds,
|
||||
uint256[] calldata ethToTokenSplits
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes memory hint);
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
pragma solidity ^0.6;
|
||||
|
||||
interface IPlatypus {
|
||||
function quotePotentialSwap(
|
||||
address fromToken,
|
||||
address toToken,
|
||||
uint256 fromAmount
|
||||
) external view returns (uint256 potentialOutcome, uint256 haircut);
|
||||
|
||||
function assetOf(address token) external view returns (address);
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract DummyLiquidityProvider
|
||||
{
|
||||
/// @dev Quotes the amount of `makerToken` that would be obtained by
|
||||
/// selling `sellAmount` of `takerToken`.
|
||||
/// @param sellAmount Amount of `takerToken` to sell.
|
||||
/// @return makerTokenAmount Amount of `makerToken` that would be obtained.
|
||||
function getSellQuote(
|
||||
address, /* takerToken */
|
||||
address, /* makerToken */
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256 makerTokenAmount)
|
||||
{
|
||||
makerTokenAmount = sellAmount - 1;
|
||||
}
|
||||
|
||||
/// @dev Quotes the amount of `takerToken` that would need to be sold in
|
||||
/// order to obtain `buyAmount` of `makerToken`.
|
||||
/// @param buyAmount Amount of `makerToken` to buy.
|
||||
/// @return takerTokenAmount Amount of `takerToken` that would need to be sold.
|
||||
function getBuyQuote(
|
||||
address, /* takerToken */
|
||||
address, /* makerToken */
|
||||
uint256 buyAmount
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256 takerTokenAmount)
|
||||
{
|
||||
takerTokenAmount = buyAmount + 1;
|
||||
}
|
||||
}
|
@@ -1,455 +0,0 @@
|
||||
// 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/ERC20BridgeSampler.sol";
|
||||
import "../src/interfaces/IKyberNetwork.sol";
|
||||
import "../src/interfaces/IUniswapV2Router01.sol";
|
||||
|
||||
|
||||
library LibDeterministicQuotes {
|
||||
|
||||
address private constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
uint256 private constant RATE_DENOMINATOR = 1 ether;
|
||||
uint256 private constant MIN_RATE = RATE_DENOMINATOR / 100;
|
||||
uint256 private constant MAX_RATE = 100 * RATE_DENOMINATOR;
|
||||
uint8 private constant MIN_DECIMALS = 4;
|
||||
uint8 private constant MAX_DECIMALS = 20;
|
||||
|
||||
function getDeterministicSellQuote(
|
||||
bytes32 salt,
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
uint256 sellAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
uint256 sellBase = uint256(10) ** getDeterministicTokenDecimals(sellToken);
|
||||
uint256 buyBase = uint256(10) ** getDeterministicTokenDecimals(buyToken);
|
||||
uint256 rate = getDeterministicRate(salt, sellToken, buyToken);
|
||||
return sellAmount * rate * buyBase / sellBase / RATE_DENOMINATOR;
|
||||
}
|
||||
|
||||
function getDeterministicBuyQuote(
|
||||
bytes32 salt,
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
uint256 buyAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 sellAmount)
|
||||
{
|
||||
uint256 sellBase = uint256(10) ** getDeterministicTokenDecimals(sellToken);
|
||||
uint256 buyBase = uint256(10) ** getDeterministicTokenDecimals(buyToken);
|
||||
uint256 rate = getDeterministicRate(salt, sellToken, buyToken);
|
||||
return buyAmount * RATE_DENOMINATOR * sellBase / rate / buyBase;
|
||||
}
|
||||
|
||||
function getDeterministicTokenDecimals(address token)
|
||||
internal
|
||||
pure
|
||||
returns (uint8 decimals)
|
||||
{
|
||||
if (token == WETH_ADDRESS) {
|
||||
return 18;
|
||||
}
|
||||
bytes32 seed = keccak256(abi.encodePacked(token));
|
||||
return uint8(uint256(seed) % (MAX_DECIMALS - MIN_DECIMALS)) + MIN_DECIMALS;
|
||||
}
|
||||
|
||||
function getDeterministicRate(bytes32 salt, address sellToken, address buyToken)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 rate)
|
||||
{
|
||||
bytes32 seed = keccak256(abi.encodePacked(salt, sellToken, buyToken));
|
||||
return uint256(seed) % (MAX_RATE - MIN_RATE) + MIN_RATE;
|
||||
}
|
||||
}
|
||||
|
||||
contract TestDeploymentConstants {
|
||||
|
||||
// solhint-disable separate-by-one-line-in-contract
|
||||
|
||||
// Mainnet addresses ///////////////////////////////////////////////////////
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
/// @dev Overridable way to get the WETH address.
|
||||
/// @return wethAddress The WETH address.
|
||||
function _getWethAddress()
|
||||
internal
|
||||
view
|
||||
returns (address wethAddress)
|
||||
{
|
||||
return WETH_ADDRESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
contract FailTrigger {
|
||||
|
||||
// Give this address a balance to force operations to fail.
|
||||
address payable constant public FAILURE_ADDRESS = 0xe9dB8717BC5DFB20aaf538b4a5a02B7791FF430C;
|
||||
|
||||
// Funds `FAILURE_ADDRESS`.
|
||||
function enableFailTrigger() external payable {
|
||||
FAILURE_ADDRESS.transfer(msg.value);
|
||||
}
|
||||
|
||||
function _revertIfShouldFail() internal view {
|
||||
if (FAILURE_ADDRESS.balance != 0) {
|
||||
revert("FAIL_TRIGGERED");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestERC20BridgeSamplerUniswapExchange is
|
||||
IUniswapExchangeQuotes,
|
||||
TestDeploymentConstants,
|
||||
FailTrigger
|
||||
{
|
||||
bytes32 constant private BASE_SALT = 0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab;
|
||||
|
||||
address public tokenAddress;
|
||||
bytes32 public salt;
|
||||
|
||||
constructor(address _tokenAddress) public {
|
||||
tokenAddress = _tokenAddress;
|
||||
salt = keccak256(abi.encodePacked(BASE_SALT, _tokenAddress));
|
||||
}
|
||||
|
||||
// Deterministic `IUniswapExchangeQuotes.getEthToTokenInputPrice()`.
|
||||
function getEthToTokenInputPrice(
|
||||
uint256 ethSold
|
||||
)
|
||||
override
|
||||
external
|
||||
view
|
||||
returns (uint256 tokensBought)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicSellQuote(
|
||||
salt,
|
||||
tokenAddress,
|
||||
_getWethAddress(),
|
||||
ethSold
|
||||
);
|
||||
}
|
||||
|
||||
// Deterministic `IUniswapExchangeQuotes.getEthToTokenOutputPrice()`.
|
||||
function getEthToTokenOutputPrice(
|
||||
uint256 tokensBought
|
||||
)
|
||||
override
|
||||
external
|
||||
view
|
||||
returns (uint256 ethSold)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicBuyQuote(
|
||||
salt,
|
||||
_getWethAddress(),
|
||||
tokenAddress,
|
||||
tokensBought
|
||||
);
|
||||
}
|
||||
|
||||
// Deterministic `IUniswapExchangeQuotes.getTokenToEthInputPrice()`.
|
||||
function getTokenToEthInputPrice(
|
||||
uint256 tokensSold
|
||||
)
|
||||
override
|
||||
external
|
||||
view
|
||||
returns (uint256 ethBought)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicSellQuote(
|
||||
salt,
|
||||
tokenAddress,
|
||||
_getWethAddress(),
|
||||
tokensSold
|
||||
);
|
||||
}
|
||||
|
||||
// Deterministic `IUniswapExchangeQuotes.getTokenToEthOutputPrice()`.
|
||||
function getTokenToEthOutputPrice(
|
||||
uint256 ethBought
|
||||
)
|
||||
override
|
||||
external
|
||||
view
|
||||
returns (uint256 tokensSold)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicBuyQuote(
|
||||
salt,
|
||||
_getWethAddress(),
|
||||
tokenAddress,
|
||||
ethBought
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestERC20BridgeSamplerUniswapV2Router01 is
|
||||
IUniswapV2Router01,
|
||||
TestDeploymentConstants,
|
||||
FailTrigger
|
||||
{
|
||||
bytes32 constant private SALT = 0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1;
|
||||
|
||||
// Deterministic `IUniswapV2Router01.getAmountsOut()`.
|
||||
function getAmountsOut(uint256 amountIn, address[] calldata path)
|
||||
override
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
require(path.length >= 2, "PATH_TOO_SHORT");
|
||||
_revertIfShouldFail();
|
||||
amounts = new uint256[](path.length);
|
||||
amounts[0] = amountIn;
|
||||
for (uint256 i = 0; i < path.length - 1; ++i) {
|
||||
amounts[i + 1] = LibDeterministicQuotes.getDeterministicSellQuote(
|
||||
SALT,
|
||||
path[i],
|
||||
path[i + 1],
|
||||
amounts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Deterministic `IUniswapV2Router01.getAmountsInt()`.
|
||||
function getAmountsIn(uint256 amountOut, address[] calldata path)
|
||||
override
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
require(path.length >= 2, "PATH_TOO_SHORT");
|
||||
_revertIfShouldFail();
|
||||
amounts = new uint256[](path.length);
|
||||
amounts[path.length - 1] = amountOut;
|
||||
for (uint256 i = path.length - 1; i > 0; --i) {
|
||||
amounts[i - 1] = LibDeterministicQuotes.getDeterministicBuyQuote(
|
||||
SALT,
|
||||
path[i - 1],
|
||||
path[i],
|
||||
amounts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
contract TestERC20BridgeSamplerKyberNetwork is
|
||||
TestDeploymentConstants,
|
||||
FailTrigger
|
||||
{
|
||||
bytes32 constant private SALT = 0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7;
|
||||
address constant public ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
|
||||
enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
|
||||
enum ProcessWithRate {NotRequired, Required}
|
||||
|
||||
// IKyberHintHandler
|
||||
function buildTokenToEthHint(
|
||||
address tokenSrc,
|
||||
TradeType /* tokenToEthType */,
|
||||
bytes32[] calldata /* tokenToEthReserveIds */,
|
||||
uint256[] calldata /* tokenToEthSplits */
|
||||
) external view returns (bytes memory hint)
|
||||
{
|
||||
return abi.encode(tokenSrc);
|
||||
}
|
||||
|
||||
function buildEthToTokenHint(
|
||||
address tokenDest,
|
||||
TradeType /* ethToTokenType */,
|
||||
bytes32[] calldata /* ethToTokenReserveIds */,
|
||||
uint256[] calldata /* ethToTokenSplits */
|
||||
) external view returns (bytes memory hint)
|
||||
{
|
||||
return abi.encode(tokenDest);
|
||||
}
|
||||
|
||||
// IKyberHintHandler
|
||||
function buildTokenToTokenHint(
|
||||
address tokenSrc,
|
||||
TradeType /* tokenToEthType */,
|
||||
bytes32[] calldata /* tokenToEthReserveIds */,
|
||||
uint256[] calldata /* tokenToEthSplits */,
|
||||
address /* tokenDest */,
|
||||
TradeType /* EthToTokenType */,
|
||||
bytes32[] calldata /* EthToTokenReserveIds */,
|
||||
uint256[] calldata /* EthToTokenSplits */
|
||||
) external view returns (bytes memory hint)
|
||||
{
|
||||
return abi.encode(tokenSrc);
|
||||
}
|
||||
|
||||
// IKyberHintHandler
|
||||
function getTradingReserves(
|
||||
address tokenSrc,
|
||||
address tokenDest,
|
||||
bool isTokenToToken,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
bytes32[] memory reserveIds,
|
||||
uint256[] memory splitValuesBps,
|
||||
ProcessWithRate processWithRate
|
||||
)
|
||||
{
|
||||
reserveIds = new bytes32[](1);
|
||||
reserveIds[0] = bytes32(uint256(1));
|
||||
splitValuesBps = new uint256[](0);
|
||||
processWithRate = ProcessWithRate.NotRequired;
|
||||
}
|
||||
|
||||
// Deterministic `IKyberNetworkProxy.getExpectedRateAfterFee()`.
|
||||
function getExpectedRateAfterFee(
|
||||
address fromToken,
|
||||
address toToken,
|
||||
uint256 /* srcQty */,
|
||||
uint256 /* fee */,
|
||||
bytes calldata /* hint */
|
||||
)
|
||||
external
|
||||
view
|
||||
returns
|
||||
(uint256 expectedRate)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
|
||||
toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
|
||||
expectedRate = LibDeterministicQuotes.getDeterministicRate(
|
||||
SALT,
|
||||
fromToken,
|
||||
toToken
|
||||
);
|
||||
}
|
||||
|
||||
// Deterministic `IKyberNetworkProxy.getExpectedRate()`.
|
||||
function getExpectedRate(
|
||||
address fromToken,
|
||||
address toToken,
|
||||
uint256
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256 expectedRate, uint256)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
|
||||
toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
|
||||
expectedRate = LibDeterministicQuotes.getDeterministicRate(
|
||||
SALT,
|
||||
fromToken,
|
||||
toToken
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestERC20BridgeSamplerUniswapExchangeFactory is
|
||||
IUniswapExchangeFactory
|
||||
{
|
||||
mapping (address => IUniswapExchangeQuotes) private _exchangesByToken;
|
||||
|
||||
// Creates Uniswap exchange contracts for tokens.
|
||||
function createTokenExchanges(address[] calldata tokenAddresses)
|
||||
external
|
||||
{
|
||||
for (uint256 i = 0; i < tokenAddresses.length; i++) {
|
||||
address tokenAddress = tokenAddresses[i];
|
||||
_exchangesByToken[tokenAddress] =
|
||||
new TestERC20BridgeSamplerUniswapExchange(tokenAddress);
|
||||
}
|
||||
}
|
||||
|
||||
// `IUniswapExchangeFactory.getExchange()`.
|
||||
function getExchange(address tokenAddress)
|
||||
override
|
||||
external
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(_exchangesByToken[tokenAddress]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestERC20BridgeSampler is
|
||||
ERC20BridgeSampler,
|
||||
FailTrigger
|
||||
{
|
||||
TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
|
||||
TestERC20BridgeSamplerUniswapV2Router01 public uniswapV2Router;
|
||||
TestERC20BridgeSamplerKyberNetwork public kyber;
|
||||
|
||||
uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1;
|
||||
|
||||
constructor() public ERC20BridgeSampler() {
|
||||
uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
|
||||
uniswapV2Router = new TestERC20BridgeSamplerUniswapV2Router01();
|
||||
kyber = new TestERC20BridgeSamplerKyberNetwork();
|
||||
}
|
||||
|
||||
// Creates Uniswap exchange contracts for tokens.
|
||||
function createTokenExchanges(address[] calldata tokenAddresses)
|
||||
external
|
||||
{
|
||||
uniswap.createTokenExchanges(tokenAddresses);
|
||||
}
|
||||
|
||||
// Overridden to return deterministic states.
|
||||
function getLimitOrderFillableTakerAmount(
|
||||
IExchange.LimitOrder memory order,
|
||||
IExchange.Signature memory,
|
||||
IExchange
|
||||
)
|
||||
override
|
||||
public
|
||||
view
|
||||
returns (uint256 fillableTakerAmount)
|
||||
{
|
||||
return uint256(keccak256(abi.encode(order.salt))) % order.takerAmount;
|
||||
}
|
||||
|
||||
// Overriden to return deterministic decimals.
|
||||
function _getTokenDecimals(address tokenAddress)
|
||||
override
|
||||
internal
|
||||
view
|
||||
returns (uint8 decimals)
|
||||
{
|
||||
return LibDeterministicQuotes.getDeterministicTokenDecimals(tokenAddress);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/asset-swapper",
|
||||
"version": "16.50.0",
|
||||
"version": "16.62.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -34,12 +34,13 @@
|
||||
"contracts:gen": "contracts-gen generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"publish:private": "yarn build && gitpkg publish",
|
||||
"sampler-size": "jq .compilerOutput.evm.deployedBytecode.object -- test/generated-artifacts/ERC20BridgeSampler.json | echo $(( $(wc -c) / 2 - 1 ))"
|
||||
"sampler-size": "jq .compilerOutput.evm.deployedBytecode.object -- test/generated-artifacts/ERC20BridgeSampler.json | echo $(( $(wc -c) / 2 - 1 ))",
|
||||
"list:deps": "yarn lerna list -l"
|
||||
},
|
||||
"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|BalancerV2Sampler|BancorSampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|FakeTaker|IBalancer|IBancor|ICurve|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2BatchSampler|BalancerV2Common|BalancerV2Sampler|BancorSampler|BancorV3Sampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|ERC20BridgeSampler|FakeTaker|GMXSampler|IBalancer|IBalancerV2Vault|IBancor|IBancorV3|ICurve|IGMX|IMStable|IMooniswap|IMultiBridge|IPlatypus|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|NativeOrderSampler|PlatypusSampler|SamplerUtils|ShellSampler|SmoothySampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler|VelodromeSampler).json",
|
||||
"postpublish": {
|
||||
"assets": []
|
||||
}
|
||||
@@ -58,22 +59,22 @@
|
||||
"registry": "git@github.com:0xProject/gitpkg-registry.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.31",
|
||||
"@0x/base-contract": "^6.4.5",
|
||||
"@0x/contract-addresses": "^6.12.0",
|
||||
"@0x/contract-wrappers": "^13.19.1",
|
||||
"@0x/contracts-erc20": "^3.3.27",
|
||||
"@0x/contracts-zero-ex": "^0.31.1",
|
||||
"@0x/dev-utils": "^4.2.11",
|
||||
"@0x/json-schemas": "^6.4.1",
|
||||
"@0x/neon-router": "^0.3.3",
|
||||
"@0x/protocol-utils": "^1.11.1",
|
||||
"@0x/assert": "^3.0.34",
|
||||
"@0x/base-contract": "^6.5.0",
|
||||
"@0x/contract-addresses": "^6.16.0",
|
||||
"@0x/contract-wrappers": "^13.20.4",
|
||||
"@0x/contracts-erc20": "^3.3.32",
|
||||
"@0x/contracts-zero-ex": "^0.35.0",
|
||||
"@0x/dev-utils": "^4.2.14",
|
||||
"@0x/json-schemas": "^6.4.4",
|
||||
"@0x/neon-router": "^0.3.5",
|
||||
"@0x/protocol-utils": "^11.15.0",
|
||||
"@0x/quote-server": "^6.0.6",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.5.0",
|
||||
"@0x/web3-wrapper": "^7.6.2",
|
||||
"@balancer-labs/sor": "0.3.2",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
"@0x/utils": "^6.5.3",
|
||||
"@0x/web3-wrapper": "^7.6.5",
|
||||
"@balancer-labs/sdk": "0.1.6",
|
||||
"@bancor/sdk": "0.2.9",
|
||||
"@ethersproject/abi": "^5.0.1",
|
||||
"@ethersproject/address": "^5.0.1",
|
||||
@@ -82,9 +83,10 @@
|
||||
"@ethersproject/strings": "^5.0.10",
|
||||
"axios": "^0.21.1",
|
||||
"axios-mock-adapter": "^1.19.0",
|
||||
"balancer-labs-sor-v1": "npm:@balancer-labs/sor@0.3.2",
|
||||
"cream-sor": "^0.3.3",
|
||||
"decimal.js": "^10.2.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereum-types": "^3.7.0",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"fast-abi": "^0.0.4",
|
||||
"graphql": "^15.4.0",
|
||||
@@ -93,20 +95,19 @@
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.7.2",
|
||||
"@0x/abi-gen": "^5.8.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.19",
|
||||
"@0x/contracts-exchange": "^3.2.38",
|
||||
"@0x/contracts-exchange-libs": "^4.3.37",
|
||||
"@0x/contracts-gen": "^2.0.43",
|
||||
"@0x/contracts-test-utils": "^5.4.18",
|
||||
"@0x/contracts-utils": "^4.8.8",
|
||||
"@0x/contracts-gen": "^2.0.46",
|
||||
"@0x/contracts-test-utils": "^5.4.23",
|
||||
"@0x/contracts-utils": "^4.8.13",
|
||||
"@0x/mesh-rpc-client": "^9.4.2",
|
||||
"@0x/migrations": "^8.1.16",
|
||||
"@0x/sol-compiler": "^4.7.8",
|
||||
"@0x/subproviders": "^6.6.2",
|
||||
"@0x/sol-compiler": "^4.8.1",
|
||||
"@0x/subproviders": "^6.6.5",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "12.12.54",
|
||||
@@ -123,7 +124,7 @@
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typemoq": "^2.1.0",
|
||||
"typescript": "4.2.2"
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -116,6 +116,15 @@ export {
|
||||
SamplerMetrics,
|
||||
} from './types';
|
||||
export { affiliateFeeUtils } from './utils/affiliate_fee_utils';
|
||||
export {
|
||||
IRfqClient,
|
||||
RfqClientV1Price,
|
||||
RfqClientV1PriceRequest,
|
||||
RfqClientV1PriceResponse,
|
||||
RfqClientV1Quote,
|
||||
RfqClientV1QuoteRequest,
|
||||
RfqClientV1QuoteResponse,
|
||||
} from './utils/irfq_client';
|
||||
export {
|
||||
DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
|
||||
DEFAULT_GAS_SCHEDULE,
|
||||
@@ -144,7 +153,6 @@ export {
|
||||
Fill,
|
||||
FillData,
|
||||
GetMarketOrdersRfqOpts,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
LiquidityProviderRegistry,
|
||||
MarketDepth,
|
||||
|
@@ -42,6 +42,7 @@ import {
|
||||
FinalUniswapV3FillData,
|
||||
LiquidityProviderFillData,
|
||||
MooniswapFillData,
|
||||
NativeRfqOrderFillData,
|
||||
OptimizedMarketBridgeOrder,
|
||||
OptimizedMarketOrder,
|
||||
UniswapV2FillData,
|
||||
@@ -60,6 +61,7 @@ import {
|
||||
isDirectSwapCompatible,
|
||||
isMultiplexBatchFillCompatible,
|
||||
isMultiplexMultiHopFillCompatible,
|
||||
requiresTransformERC20,
|
||||
} from './quote_consumer_utils';
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
@@ -73,9 +75,7 @@ const PANCAKE_SWAP_FORKS = [
|
||||
ERC20BridgeSource.BakerySwap,
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.ApeSwap,
|
||||
ERC20BridgeSource.CafeSwap,
|
||||
ERC20BridgeSource.CheeseSwap,
|
||||
ERC20BridgeSource.JulSwap,
|
||||
];
|
||||
const FAKE_PROVIDER: any = {
|
||||
sendAsync(): void {
|
||||
@@ -220,9 +220,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
ERC20BridgeSource.BakerySwap,
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.ApeSwap,
|
||||
ERC20BridgeSource.CafeSwap,
|
||||
ERC20BridgeSource.CheeseSwap,
|
||||
ERC20BridgeSource.JulSwap,
|
||||
])
|
||||
) {
|
||||
const source = slippedOrders[0].source;
|
||||
@@ -278,7 +276,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
|
||||
if (
|
||||
this.chainId === ChainId.Mainnet &&
|
||||
isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.Curve, ERC20BridgeSource.Swerve]) &&
|
||||
isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.Curve]) &&
|
||||
// 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
|
||||
@@ -333,6 +331,49 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
};
|
||||
}
|
||||
|
||||
// RFQT VIP
|
||||
if (
|
||||
[ChainId.Mainnet, ChainId.Polygon].includes(this.chainId) &&
|
||||
!isToETH &&
|
||||
!isFromETH &&
|
||||
quote.orders.every(o => o.type === FillQuoteTransformerOrderType.Rfq) &&
|
||||
!requiresTransformERC20(optsWithDefaults)
|
||||
) {
|
||||
const rfqOrdersData = quote.orders.map(o => o.fillData as NativeRfqOrderFillData);
|
||||
const fillAmountPerOrder = (() => {
|
||||
// Don't think order taker amounts are clipped to actual sell amount
|
||||
// (the last one might be too large) so figure them out manually.
|
||||
let remaining = sellAmount;
|
||||
const fillAmounts = [];
|
||||
for (const o of quote.orders) {
|
||||
const fillAmount = BigNumber.min(o.takerAmount, remaining);
|
||||
fillAmounts.push(fillAmount);
|
||||
remaining = remaining.minus(fillAmount);
|
||||
}
|
||||
return fillAmounts;
|
||||
})();
|
||||
const callData =
|
||||
quote.orders.length === 1
|
||||
? this._exchangeProxy
|
||||
.fillRfqOrder(rfqOrdersData[0].order, rfqOrdersData[0].signature, fillAmountPerOrder[0])
|
||||
.getABIEncodedTransactionData()
|
||||
: this._exchangeProxy
|
||||
.batchFillRfqOrders(
|
||||
rfqOrdersData.map(d => d.order),
|
||||
rfqOrdersData.map(d => d.signature),
|
||||
fillAmountPerOrder,
|
||||
true,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
return {
|
||||
calldataHexString: callData,
|
||||
ethAmount: ZERO_AMOUNT,
|
||||
toAddress: this._exchangeProxy.address,
|
||||
allowanceTarget: this._exchangeProxy.address,
|
||||
gasOverhead: ZERO_AMOUNT,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) {
|
||||
return {
|
||||
calldataHexString: this._encodeMultiplexBatchFillCalldata(
|
||||
|
@@ -25,6 +25,7 @@ import {
|
||||
SwapQuoterRfqOpts,
|
||||
} from './types';
|
||||
import { assert } from './utils/assert';
|
||||
import { IRfqClient } from './utils/irfq_client';
|
||||
import { MarketOperationUtils } from './utils/market_operation_utils';
|
||||
import { BancorService } from './utils/market_operation_utils/bancor_service';
|
||||
import { SAMPLER_ADDRESS, SOURCE_FLAGS, ZERO_AMOUNT } from './utils/market_operation_utils/constants';
|
||||
@@ -327,6 +328,7 @@ export class SwapQuoter {
|
||||
assetFillAmount: BigNumber,
|
||||
marketOperation: MarketOperation,
|
||||
options: Partial<SwapQuoteRequestOpts>,
|
||||
rfqClient?: IRfqClient | undefined,
|
||||
): Promise<SwapQuote> {
|
||||
assert.isETHAddressHex('makerToken', makerToken);
|
||||
assert.isETHAddressHex('takerToken', takerToken);
|
||||
@@ -381,6 +383,7 @@ export class SwapQuoter {
|
||||
this.expiryBufferMs,
|
||||
rfqtOptions?.metricsProxy,
|
||||
);
|
||||
calcOpts.rfqt.rfqClient = rfqClient;
|
||||
}
|
||||
|
||||
const result: OptimizerResultWithReport = await this._marketOperationUtils.getOptimizerResultAsync(
|
||||
@@ -519,7 +522,7 @@ function createSwapQuote(
|
||||
: calculateQuoteInfo(optimizedOrders, operation, assetFillAmount, gasPrice, gasSchedule, slippage);
|
||||
|
||||
// Put together the swap quote
|
||||
const { makerTokenDecimals, takerTokenDecimals } = optimizerResult.marketSideLiquidity;
|
||||
const { makerTokenDecimals, takerTokenDecimals, blockNumber } = optimizerResult.marketSideLiquidity;
|
||||
const swapQuote = {
|
||||
makerToken,
|
||||
takerToken,
|
||||
@@ -536,6 +539,7 @@ function createSwapQuote(
|
||||
extendedQuoteReportSources,
|
||||
isTwoHop,
|
||||
priceComparisonsReport,
|
||||
blockNumber,
|
||||
};
|
||||
|
||||
if (operation === MarketOperation.Buy) {
|
||||
|
@@ -179,6 +179,7 @@ export interface SwapQuoteBase {
|
||||
takerTokenDecimals: number;
|
||||
takerAmountPerEth: BigNumber;
|
||||
makerAmountPerEth: BigNumber;
|
||||
blockNumber: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -17,7 +17,10 @@ import {
|
||||
|
||||
const SUCCESS_CODE = 201;
|
||||
|
||||
function getAltMarketInfo(
|
||||
/**
|
||||
* Returns the AltOffering if it exists for a given pair
|
||||
*/
|
||||
export function getAltMarketInfo(
|
||||
offerings: AltOffering[],
|
||||
buyTokenAddress: string,
|
||||
sellTokenAddress: string,
|
||||
|
59
packages/asset-swapper/src/utils/irfq_client.ts
Normal file
59
packages/asset-swapper/src/utils/irfq_client.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { RfqOrder, Signature } from '@0x/protocol-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { AltRfqMakerAssetOfferings } from '../types';
|
||||
|
||||
export interface RfqClientV1PriceRequest {
|
||||
altRfqAssetOfferings: AltRfqMakerAssetOfferings | undefined;
|
||||
assetFillAmount: BigNumber;
|
||||
chainId: number;
|
||||
comparisonPrice: BigNumber | undefined;
|
||||
integratorId: string;
|
||||
intentOnFilling: boolean;
|
||||
makerToken: string;
|
||||
marketOperation: 'Sell' | 'Buy';
|
||||
takerAddress: string;
|
||||
takerToken: string;
|
||||
txOrigin: string;
|
||||
}
|
||||
|
||||
export interface RfqClientV1QuoteRequest extends RfqClientV1PriceRequest {}
|
||||
|
||||
export interface RfqClientV1Price {
|
||||
expiry: BigNumber;
|
||||
kind: 'rfq' | 'otc';
|
||||
makerAmount: BigNumber;
|
||||
makerToken: string;
|
||||
makerUri: string;
|
||||
takerAmount: BigNumber;
|
||||
takerToken: string;
|
||||
}
|
||||
|
||||
export interface RfqClientV1PriceResponse {
|
||||
prices: RfqClientV1Price[];
|
||||
}
|
||||
|
||||
export interface RfqClientV1Quote {
|
||||
makerUri: string;
|
||||
order: RfqOrder;
|
||||
signature: Signature;
|
||||
}
|
||||
|
||||
export interface RfqClientV1QuoteResponse {
|
||||
quotes: RfqClientV1Quote[];
|
||||
}
|
||||
|
||||
/**
|
||||
* IRfqClient is an interface that defines how to connect with an Rfq system.
|
||||
*/
|
||||
export interface IRfqClient {
|
||||
/**
|
||||
* Fetches a list of "indicative quotes" or prices from a remote Rfq server
|
||||
*/
|
||||
getV1PricesAsync(request: RfqClientV1PriceRequest): Promise<RfqClientV1PriceResponse>;
|
||||
|
||||
/**
|
||||
* Fetches a list of "firm quotes" or signed quotes from a remote Rfq server.
|
||||
*/
|
||||
getV1QuotesAsync(request: RfqClientV1QuoteRequest): Promise<RfqClientV1QuoteResponse>;
|
||||
}
|
@@ -1,12 +1,12 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import {
|
||||
ACRYPTOS_BSC_INFOS,
|
||||
APESWAP_ROUTER_BY_CHAIN_ID,
|
||||
BAKERYSWAP_ROUTER_BY_CHAIN_ID,
|
||||
BELT_BSC_INFOS,
|
||||
CAFESWAP_ROUTER_BY_CHAIN_ID,
|
||||
BISWAP_ROUTER_BY_CHAIN_ID,
|
||||
CHEESESWAP_ROUTER_BY_CHAIN_ID,
|
||||
COMETHSWAP_ROUTER_BY_CHAIN_ID,
|
||||
COMPONENT_POOLS_BY_CHAIN_ID,
|
||||
@@ -25,12 +25,11 @@ import {
|
||||
FIREBIRDONESWAP_BSC_INFOS,
|
||||
FIREBIRDONESWAP_POLYGON_INFOS,
|
||||
IRONSWAP_POLYGON_INFOS,
|
||||
JETSWAP_ROUTER_BY_CHAIN_ID,
|
||||
JULSWAP_ROUTER_BY_CHAIN_ID,
|
||||
KYBER_BANNED_RESERVES,
|
||||
KYBER_BRIDGED_LIQUIDITY_PREFIX,
|
||||
KNIGHTSWAP_ROUTER_BY_CHAIN_ID,
|
||||
MAX_DODOV2_POOLS_QUERIED,
|
||||
MAX_KYBER_RESERVES_QUERIED,
|
||||
MDEX_ROUTER_BY_CHAIN_ID,
|
||||
MESHSWAP_ROUTER_BY_CHAIN_ID,
|
||||
MOBIUSMONEY_CELO_INFOS,
|
||||
MORPHEUSSWAP_ROUTER_BY_CHAIN_ID,
|
||||
MSTABLE_POOLS_BY_CHAIN_ID,
|
||||
NERVE_BSC_INFOS,
|
||||
@@ -38,18 +37,16 @@ import {
|
||||
PANCAKESWAP_ROUTER_BY_CHAIN_ID,
|
||||
PANCAKESWAPV2_ROUTER_BY_CHAIN_ID,
|
||||
PANGOLIN_ROUTER_BY_CHAIN_ID,
|
||||
POLYDEX_ROUTER_BY_CHAIN_ID,
|
||||
PLATYPUS_AVALANCHE_INFOS,
|
||||
QUICKSWAP_ROUTER_BY_CHAIN_ID,
|
||||
SADDLE_MAINNET_INFOS,
|
||||
SHELL_POOLS_BY_CHAIN_ID,
|
||||
SHIBASWAP_ROUTER_BY_CHAIN_ID,
|
||||
SMOOTHY_BSC_INFOS,
|
||||
SMOOTHY_MAINNET_INFOS,
|
||||
SNOWSWAP_MAINNET_INFOS,
|
||||
SPIRITSWAP_ROUTER_BY_CHAIN_ID,
|
||||
SPOOKYSWAP_ROUTER_BY_CHAIN_ID,
|
||||
SUSHISWAP_ROUTER_BY_CHAIN_ID,
|
||||
SWERVE_MAINNET_INFOS,
|
||||
SYNAPSE_AVALANCHE_INFOS,
|
||||
SYNAPSE_BSC_INFOS,
|
||||
SYNAPSE_FANTOM_INFOS,
|
||||
@@ -61,35 +58,15 @@ import {
|
||||
UNISWAPV2_ROUTER_BY_CHAIN_ID,
|
||||
WAULTSWAP_ROUTER_BY_CHAIN_ID,
|
||||
XSIGMA_MAINNET_INFOS,
|
||||
YOSHI_ROUTER_BY_CHAIN_ID,
|
||||
} from './constants';
|
||||
import { CurveInfo, ERC20BridgeSource } from './types';
|
||||
|
||||
/**
|
||||
* Filter Kyber reserves which should not be used (0xbb bridged reserves)
|
||||
* @param reserveId Kyber reserveId
|
||||
*/
|
||||
export function isAllowedKyberReserveId(reserveId: string): boolean {
|
||||
return (
|
||||
reserveId !== NULL_BYTES &&
|
||||
!reserveId.startsWith(KYBER_BRIDGED_LIQUIDITY_PREFIX) &&
|
||||
!KYBER_BANNED_RESERVES.includes(reserveId)
|
||||
);
|
||||
}
|
||||
import { CurveInfo, ERC20BridgeSource, PlatypusInfo } from './types';
|
||||
|
||||
// tslint:disable-next-line: completed-docs ban-types
|
||||
export function isValidAddress(address: string | String): address is string {
|
||||
return (typeof address === 'string' || address instanceof String) && address.toString() !== NULL_ADDRESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offsets to be used to discover Kyber reserves
|
||||
*/
|
||||
export function getKyberOffsets(): BigNumber[] {
|
||||
return Array(MAX_KYBER_RESERVES_QUERIED)
|
||||
.fill(0)
|
||||
.map((_v, i) => new BigNumber(i));
|
||||
}
|
||||
|
||||
// tslint:disable completed-docs
|
||||
export function getDodoV2Offsets(): BigNumber[] {
|
||||
return Array(MAX_DODOV2_POOLS_QUERIED)
|
||||
@@ -224,32 +201,6 @@ export function getCurveV2InfosForPair(chainId: ChainId, takerToken: string, mak
|
||||
}
|
||||
}
|
||||
|
||||
export function getSwerveInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
|
||||
if (chainId !== ChainId.Mainnet) {
|
||||
return [];
|
||||
}
|
||||
return Object.values(SWERVE_MAINNET_INFOS).filter(c =>
|
||||
[makerToken, takerToken].every(
|
||||
t =>
|
||||
(c.tokens.includes(t) && c.metaTokens === undefined) ||
|
||||
(c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function getSnowSwapInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
|
||||
if (chainId !== ChainId.Mainnet) {
|
||||
return [];
|
||||
}
|
||||
return Object.values(SNOWSWAP_MAINNET_INFOS).filter(c =>
|
||||
[makerToken, takerToken].every(
|
||||
t =>
|
||||
(c.tokens.includes(t) && c.metaTokens === undefined) ||
|
||||
(c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function getNerveInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
|
||||
if (chainId !== ChainId.BSC) {
|
||||
return [];
|
||||
@@ -449,6 +400,27 @@ export function getAcryptosInfosForPair(chainId: ChainId, takerToken: string, ma
|
||||
),
|
||||
);
|
||||
}
|
||||
export function getMobiusMoneyInfoForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
|
||||
if (chainId !== ChainId.Celo) {
|
||||
return [];
|
||||
}
|
||||
return Object.values(MOBIUSMONEY_CELO_INFOS).filter(c =>
|
||||
[makerToken, takerToken].every(
|
||||
t =>
|
||||
(c.tokens.includes(t) && c.metaTokens === undefined) ||
|
||||
(c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function getPlatypusInfoForPair(chainId: ChainId, takerToken: string, makerToken: string): PlatypusInfo[] {
|
||||
if (chainId !== ChainId.Avalanche) {
|
||||
return [];
|
||||
}
|
||||
return Object.values(PLATYPUS_AVALANCHE_INFOS).filter(c =>
|
||||
[makerToken, takerToken].every(t => c.tokens.includes(t)),
|
||||
);
|
||||
}
|
||||
|
||||
export function getShellLikeInfosForPair(
|
||||
chainId: ChainId,
|
||||
@@ -480,8 +452,6 @@ export function getCurveLikeInfosForPair(
|
||||
source:
|
||||
| ERC20BridgeSource.Curve
|
||||
| ERC20BridgeSource.CurveV2
|
||||
| ERC20BridgeSource.Swerve
|
||||
| ERC20BridgeSource.SnowSwap
|
||||
| ERC20BridgeSource.Nerve
|
||||
| ERC20BridgeSource.Synapse
|
||||
| ERC20BridgeSource.Belt
|
||||
@@ -491,7 +461,8 @@ export function getCurveLikeInfosForPair(
|
||||
| ERC20BridgeSource.IronSwap
|
||||
| ERC20BridgeSource.XSigma
|
||||
| ERC20BridgeSource.FirebirdOneSwap
|
||||
| ERC20BridgeSource.ACryptos,
|
||||
| ERC20BridgeSource.ACryptos
|
||||
| ERC20BridgeSource.MobiusMoney,
|
||||
): CurveDetailedInfo[] {
|
||||
let pools: CurveInfo[] = [];
|
||||
switch (source) {
|
||||
@@ -501,12 +472,6 @@ export function getCurveLikeInfosForPair(
|
||||
case ERC20BridgeSource.CurveV2:
|
||||
pools = getCurveV2InfosForPair(chainId, takerToken, makerToken);
|
||||
break;
|
||||
case ERC20BridgeSource.Swerve:
|
||||
pools = getSwerveInfosForPair(chainId, takerToken, makerToken);
|
||||
break;
|
||||
case ERC20BridgeSource.SnowSwap:
|
||||
pools = getSnowSwapInfosForPair(chainId, takerToken, makerToken);
|
||||
break;
|
||||
case ERC20BridgeSource.Nerve:
|
||||
pools = getNerveInfosForPair(chainId, takerToken, makerToken);
|
||||
break;
|
||||
@@ -537,6 +502,9 @@ export function getCurveLikeInfosForPair(
|
||||
case ERC20BridgeSource.ACryptos:
|
||||
pools = getAcryptosInfosForPair(chainId, takerToken, makerToken);
|
||||
break;
|
||||
case ERC20BridgeSource.MobiusMoney:
|
||||
pools = getMobiusMoneyInfoForPair(chainId, takerToken, makerToken);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown Curve like source ${source}`);
|
||||
}
|
||||
@@ -557,22 +525,23 @@ export function uniswapV2LikeRouterAddress(
|
||||
| ERC20BridgeSource.PancakeSwapV2
|
||||
| ERC20BridgeSource.BakerySwap
|
||||
| ERC20BridgeSource.ApeSwap
|
||||
| ERC20BridgeSource.CafeSwap
|
||||
| ERC20BridgeSource.CheeseSwap
|
||||
| ERC20BridgeSource.JulSwap
|
||||
| ERC20BridgeSource.QuickSwap
|
||||
| ERC20BridgeSource.ComethSwap
|
||||
| ERC20BridgeSource.Dfyn
|
||||
| ERC20BridgeSource.WaultSwap
|
||||
| ERC20BridgeSource.Polydex
|
||||
| ERC20BridgeSource.ShibaSwap
|
||||
| ERC20BridgeSource.JetSwap
|
||||
| ERC20BridgeSource.TraderJoe
|
||||
| ERC20BridgeSource.Pangolin
|
||||
| ERC20BridgeSource.UbeSwap
|
||||
| ERC20BridgeSource.MorpheusSwap
|
||||
| ERC20BridgeSource.SpookySwap
|
||||
| ERC20BridgeSource.SpiritSwap,
|
||||
| ERC20BridgeSource.SpiritSwap
|
||||
| ERC20BridgeSource.BiSwap
|
||||
| ERC20BridgeSource.Yoshi
|
||||
| ERC20BridgeSource.MDex
|
||||
| ERC20BridgeSource.KnightSwap
|
||||
| ERC20BridgeSource.MeshSwap,
|
||||
): string {
|
||||
switch (source) {
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
@@ -589,12 +558,8 @@ export function uniswapV2LikeRouterAddress(
|
||||
return BAKERYSWAP_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];
|
||||
case ERC20BridgeSource.QuickSwap:
|
||||
return QUICKSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.ComethSwap:
|
||||
@@ -603,12 +568,8 @@ export function uniswapV2LikeRouterAddress(
|
||||
return DFYN_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.WaultSwap:
|
||||
return WAULTSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.Polydex:
|
||||
return POLYDEX_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
return SHIBASWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
return JETSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
return PANGOLIN_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
@@ -621,6 +582,16 @@ export function uniswapV2LikeRouterAddress(
|
||||
return SPOOKYSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.SpiritSwap:
|
||||
return SPIRITSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.BiSwap:
|
||||
return BISWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.Yoshi:
|
||||
return YOSHI_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.MeshSwap:
|
||||
return MESHSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.MDex:
|
||||
return MDEX_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.KnightSwap:
|
||||
return KNIGHTSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
default:
|
||||
throw new Error(`Unknown UniswapV2 like source ${source}`);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -175,9 +175,9 @@ export function dexSamplesToFills(
|
||||
const { source, fillData } = sample;
|
||||
const input = sample.input.minus(prevSample ? prevSample.input : 0);
|
||||
const output = sample.output.minus(prevSample ? prevSample.output : 0);
|
||||
const fee = fees[source] === undefined ? 0 : fees[source]!(sample.fillData) || 0;
|
||||
let penalty = ZERO_AMOUNT;
|
||||
if (i === 0) {
|
||||
const fee = fees[source] === undefined ? 0 : fees[source]!(sample.fillData) || 0;
|
||||
// Only the first fill in a DEX path incurs a penalty.
|
||||
penalty = ethToOutputAmount({
|
||||
input,
|
||||
|
@@ -4,12 +4,15 @@ import * as _ from 'lodash';
|
||||
|
||||
import { DEFAULT_INFO_LOGGER, INVALID_SIGNATURE } from '../../constants';
|
||||
import {
|
||||
AltRfqMakerAssetOfferings,
|
||||
AssetSwapperContractAddresses,
|
||||
MarketOperation,
|
||||
NativeOrderWithFillableAmounts,
|
||||
SignedNativeOrder,
|
||||
} from '../../types';
|
||||
import { QuoteRequestor } from '../quote_requestor';
|
||||
import { getAltMarketInfo } from '../alt_mm_implementation_utils';
|
||||
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../quote_requestor';
|
||||
import { toSignedNativeOrder } from '../rfq_client_mappers';
|
||||
import {
|
||||
getNativeAdjustedFillableAmountsFromMakerAmount,
|
||||
getNativeAdjustedFillableAmountsFromTakerAmount,
|
||||
@@ -42,7 +45,7 @@ import { createFills } from './fills';
|
||||
import { getBestTwoHopQuote } from './multihop_utils';
|
||||
import { createOrdersFromTwoHopSample } from './orders';
|
||||
import { Path, PathPenaltyOpts } from './path';
|
||||
import { fillsToSortedPaths, findOptimalPathJSAsync, findOptimalRustPathFromSamples } from './path_optimizer';
|
||||
import { findOptimalPathJSAsync, findOptimalRustPathFromSamples } from './path_optimizer';
|
||||
import { DexOrderSampler, getSampleAmounts } from './sampler';
|
||||
import { SourceFilters } from './source_filters';
|
||||
import {
|
||||
@@ -241,6 +244,7 @@ export class MarketOperationUtils {
|
||||
dexQuotes,
|
||||
},
|
||||
isRfqSupported,
|
||||
blockNumber: blockNumber.toNumber(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -269,6 +273,7 @@ export class MarketOperationUtils {
|
||||
|
||||
// Call the sampler contract.
|
||||
const samplerPromise = this._sampler.executeAsync(
|
||||
this._sampler.getBlockNumber(),
|
||||
this._sampler.getTokenDecimals([makerToken, takerToken]),
|
||||
// Get native order fillable amounts.
|
||||
this._sampler.getLimitOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchangeProxy),
|
||||
@@ -302,6 +307,7 @@ export class MarketOperationUtils {
|
||||
|
||||
const [
|
||||
[
|
||||
blockNumber,
|
||||
tokenDecimals,
|
||||
orderFillableMakerAmounts,
|
||||
ethToMakerAssetRate,
|
||||
@@ -342,6 +348,7 @@ export class MarketOperationUtils {
|
||||
dexQuotes,
|
||||
},
|
||||
isRfqSupported,
|
||||
blockNumber: blockNumber.toNumber(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -372,6 +379,7 @@ export class MarketOperationUtils {
|
||||
const feeSourceFilters = this._feeSources.exclude(_opts.excludedFeeSources);
|
||||
|
||||
const ops = [
|
||||
this._sampler.getBlockNumber(),
|
||||
...batchNativeOrders.map(orders =>
|
||||
this._sampler.getLimitOrderFillableMakerAmounts(orders, this.contractAddresses.exchangeProxy),
|
||||
),
|
||||
@@ -396,13 +404,15 @@ export class MarketOperationUtils {
|
||||
),
|
||||
];
|
||||
|
||||
const executeResults = await this._sampler.executeBatchAsync(ops);
|
||||
const [blockNumberRaw, ...executeResults] = await this._sampler.executeBatchAsync(ops);
|
||||
const batchOrderFillableMakerAmounts = executeResults.splice(0, batchNativeOrders.length) as BigNumber[][];
|
||||
const batchEthToTakerAssetRate = executeResults.splice(0, batchNativeOrders.length) as BigNumber[];
|
||||
const batchDexQuotes = executeResults.splice(0, batchNativeOrders.length) as DexSample[][][];
|
||||
const batchTokenDecimals = executeResults.splice(0, batchNativeOrders.length) as number[][];
|
||||
const inputAmountPerEth = ZERO_AMOUNT;
|
||||
|
||||
const blockNumber: number = (blockNumberRaw as BigNumber).toNumber();
|
||||
|
||||
return Promise.all(
|
||||
batchNativeOrders.map(async (nativeOrders, i) => {
|
||||
if (nativeOrders.length === 0) {
|
||||
@@ -435,6 +445,7 @@ export class MarketOperationUtils {
|
||||
twoHopQuotes: [],
|
||||
},
|
||||
isRfqSupported: false,
|
||||
blockNumber,
|
||||
},
|
||||
{
|
||||
bridgeSlippage: _opts.bridgeSlippage,
|
||||
@@ -493,18 +504,6 @@ export class MarketOperationUtils {
|
||||
} as NativeOrderWithFillableAmounts),
|
||||
);
|
||||
|
||||
// Convert native orders and dex quotes into `Fill` objects.
|
||||
const fills = createFills({
|
||||
side,
|
||||
orders: [...nativeOrders, ...augmentedRfqtIndicativeQuotes],
|
||||
dexQuotes,
|
||||
targetInput: inputAmount,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
excludedSources: opts.excludedSources,
|
||||
feeSchedule: opts.feeSchedule,
|
||||
});
|
||||
|
||||
// Find the optimal path.
|
||||
const penaltyOpts: PathPenaltyOpts = {
|
||||
outputAmountPerEth,
|
||||
@@ -517,13 +516,11 @@ export class MarketOperationUtils {
|
||||
const takerAmountPerEth = side === MarketOperation.Sell ? inputAmountPerEth : outputAmountPerEth;
|
||||
const makerAmountPerEth = side === MarketOperation.Sell ? outputAmountPerEth : inputAmountPerEth;
|
||||
|
||||
// Find the unoptimized best rate to calculate savings from optimizer
|
||||
const _unoptimizedPath = fillsToSortedPaths(fills, side, inputAmount, penaltyOpts)[0];
|
||||
const unoptimizedPath = _unoptimizedPath ? _unoptimizedPath.collapse(orderOpts) : undefined;
|
||||
|
||||
let fills: Fill[][];
|
||||
// Find the optimal path using Rust router if enabled, otherwise fallback to JS Router
|
||||
let optimalPath: Path | undefined;
|
||||
if (SHOULD_USE_RUST_ROUTER) {
|
||||
fills = [[]];
|
||||
optimalPath = findOptimalRustPathFromSamples(
|
||||
side,
|
||||
dexQuotes,
|
||||
@@ -536,6 +533,18 @@ export class MarketOperationUtils {
|
||||
opts.samplerMetrics,
|
||||
);
|
||||
} else {
|
||||
// Convert native orders and dex quotes into `Fill` objects.
|
||||
fills = createFills({
|
||||
side,
|
||||
orders: [...nativeOrders, ...augmentedRfqtIndicativeQuotes],
|
||||
dexQuotes,
|
||||
targetInput: inputAmount,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
excludedSources: opts.excludedSources,
|
||||
feeSchedule: opts.feeSchedule,
|
||||
});
|
||||
|
||||
optimalPath = await findOptimalPathJSAsync(
|
||||
side,
|
||||
fills,
|
||||
@@ -561,7 +570,6 @@ export class MarketOperationUtils {
|
||||
sourceFlags: SOURCE_FLAGS[ERC20BridgeSource.MultiHop],
|
||||
marketSideLiquidity,
|
||||
adjustedRate: bestTwoHopRate,
|
||||
unoptimizedPath,
|
||||
takerAmountPerEth,
|
||||
makerAmountPerEth,
|
||||
};
|
||||
@@ -573,7 +581,10 @@ export class MarketOperationUtils {
|
||||
}
|
||||
|
||||
// Generate a fallback path if required
|
||||
await this._addOptionalFallbackAsync(side, inputAmount, optimalPath, dexQuotes, fills, opts, penaltyOpts);
|
||||
// TODO(kimpers): Will experiment with disabling this and see how it affects revert rate
|
||||
// to avoid yet another router roundtrip
|
||||
// TODO: clean this up if we don't need it
|
||||
// await this._addOptionalFallbackAsync(side, inputAmount, optimalPath, dexQuotes, fills, opts, penaltyOpts);
|
||||
const collapsedPath = optimalPath.collapse(orderOpts);
|
||||
|
||||
return {
|
||||
@@ -582,7 +593,6 @@ export class MarketOperationUtils {
|
||||
sourceFlags: collapsedPath.sourceFlags,
|
||||
marketSideLiquidity,
|
||||
adjustedRate: optimalPathRate,
|
||||
unoptimizedPath,
|
||||
takerAmountPerEth,
|
||||
makerAmountPerEth,
|
||||
};
|
||||
@@ -656,17 +666,49 @@ export class MarketOperationUtils {
|
||||
// Timing of RFQT lifecycle
|
||||
const timeStart = new Date().getTime();
|
||||
const { makerToken, takerToken } = nativeOrders[0].order;
|
||||
|
||||
// Filter Alt Rfq Maker Asset Offerings to the current pair
|
||||
const filteredOfferings: AltRfqMakerAssetOfferings = {};
|
||||
if (rfqt.altRfqAssetOfferings) {
|
||||
const endpoints = Object.keys(rfqt.altRfqAssetOfferings);
|
||||
for (const endpoint of endpoints) {
|
||||
// Get the current pair if being offered
|
||||
const offering = getAltMarketInfo(rfqt.altRfqAssetOfferings[endpoint], makerToken, takerToken);
|
||||
if (offering) {
|
||||
filteredOfferings[endpoint] = [offering];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rfqt.isIndicative) {
|
||||
// An indicative quote is being requested, and indicative quotes price-aware enabled
|
||||
// Make the RFQT request and then re-run the sampler if new orders come back.
|
||||
const indicativeQuotes = await rfqt.quoteRequestor.requestRfqtIndicativeQuotesAsync(
|
||||
makerToken,
|
||||
takerToken,
|
||||
amount,
|
||||
side,
|
||||
wholeOrderPrice,
|
||||
rfqt,
|
||||
);
|
||||
|
||||
const indicativeQuotes =
|
||||
rfqt.rfqClient !== undefined
|
||||
? ((
|
||||
await rfqt.rfqClient.getV1PricesAsync({
|
||||
altRfqAssetOfferings: filteredOfferings,
|
||||
assetFillAmount: amount,
|
||||
chainId: this._sampler.chainId,
|
||||
comparisonPrice: wholeOrderPrice,
|
||||
integratorId: rfqt.integrator.integratorId,
|
||||
intentOnFilling: rfqt.intentOnFilling,
|
||||
makerToken,
|
||||
marketOperation: side,
|
||||
takerAddress: rfqt.takerAddress,
|
||||
takerToken,
|
||||
txOrigin: rfqt.txOrigin,
|
||||
})
|
||||
).prices as V4RFQIndicativeQuoteMM[])
|
||||
: await rfqt.quoteRequestor.requestRfqtIndicativeQuotesAsync(
|
||||
makerToken,
|
||||
takerToken,
|
||||
amount,
|
||||
side,
|
||||
wholeOrderPrice,
|
||||
rfqt,
|
||||
);
|
||||
const deltaTime = new Date().getTime() - timeStart;
|
||||
DEFAULT_INFO_LOGGER({
|
||||
rfqQuoteType: 'indicative',
|
||||
@@ -680,14 +722,31 @@ export class MarketOperationUtils {
|
||||
} else {
|
||||
// A firm quote is being requested, and firm quotes price-aware enabled.
|
||||
// Ensure that `intentOnFilling` is enabled and make the request.
|
||||
const firmQuotes = await rfqt.quoteRequestor.requestRfqtFirmQuotesAsync(
|
||||
makerToken,
|
||||
takerToken,
|
||||
amount,
|
||||
side,
|
||||
wholeOrderPrice,
|
||||
rfqt,
|
||||
);
|
||||
const firmQuotes =
|
||||
rfqt.rfqClient !== undefined
|
||||
? (
|
||||
await rfqt.rfqClient.getV1QuotesAsync({
|
||||
altRfqAssetOfferings: filteredOfferings,
|
||||
assetFillAmount: amount,
|
||||
chainId: this._sampler.chainId,
|
||||
comparisonPrice: wholeOrderPrice,
|
||||
integratorId: rfqt.integrator.integratorId,
|
||||
intentOnFilling: rfqt.intentOnFilling,
|
||||
makerToken,
|
||||
marketOperation: side,
|
||||
takerAddress: rfqt.takerAddress,
|
||||
takerToken,
|
||||
txOrigin: rfqt.txOrigin,
|
||||
})
|
||||
).quotes.map(toSignedNativeOrder)
|
||||
: await rfqt.quoteRequestor.requestRfqtFirmQuotesAsync(
|
||||
makerToken,
|
||||
takerToken,
|
||||
amount,
|
||||
side,
|
||||
wholeOrderPrice,
|
||||
rfqt,
|
||||
);
|
||||
const deltaTime = new Date().getTime() - timeStart;
|
||||
DEFAULT_INFO_LOGGER({
|
||||
rfqQuoteType: 'firm',
|
||||
@@ -770,7 +829,7 @@ export class MarketOperationUtils {
|
||||
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)) {
|
||||
if (!cache || cache.isFresh(takerToken, makerToken)) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return cache.getFreshPoolsForPairAsync(takerToken, makerToken);
|
||||
@@ -778,6 +837,8 @@ export class MarketOperationUtils {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(kimpers): Remove this when we know that it's safe to drop the fallbacks on native orders
|
||||
// tslint:disable-next-line: prefer-function-over-method
|
||||
private async _addOptionalFallbackAsync(
|
||||
side: MarketOperation,
|
||||
@@ -843,6 +904,7 @@ export class MarketOperationUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// tslint:disable: max-file-line-count
|
||||
|
@@ -8,6 +8,7 @@ import {
|
||||
AaveV2FillData,
|
||||
AggregationError,
|
||||
BalancerFillData,
|
||||
BalancerV2BatchSwapFillData,
|
||||
BalancerV2FillData,
|
||||
BancorFillData,
|
||||
CollapsedFill,
|
||||
@@ -20,8 +21,8 @@ import {
|
||||
FinalUniswapV3FillData,
|
||||
GeistFillData,
|
||||
GenericRouterFillData,
|
||||
GMXFillData,
|
||||
KyberDmmFillData,
|
||||
KyberFillData,
|
||||
LidoFillData,
|
||||
LiquidityProviderFillData,
|
||||
MakerPsmFillData,
|
||||
@@ -34,10 +35,12 @@ import {
|
||||
OptimizedMarketOrder,
|
||||
OptimizedMarketOrderBase,
|
||||
OrderDomain,
|
||||
PlatypusFillData,
|
||||
ShellFillData,
|
||||
UniswapV2FillData,
|
||||
UniswapV3FillData,
|
||||
UniswapV3PathAmount,
|
||||
VelodromeFillData,
|
||||
} from './types';
|
||||
|
||||
// tslint:disable completed-docs
|
||||
@@ -86,11 +89,9 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
case ERC20BridgeSource.Balancer:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Balancer, 'Balancer');
|
||||
case ERC20BridgeSource.BalancerV2:
|
||||
return encodeBridgeSourceId(BridgeProtocol.BalancerV2, 'BalancerV2');
|
||||
return encodeBridgeSourceId(BridgeProtocol.BalancerV2Batch, 'BalancerV2');
|
||||
case ERC20BridgeSource.Bancor:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Bancor, 'Bancor');
|
||||
// case ERC20BridgeSource.CoFiX:
|
||||
// return encodeBridgeSourceId(BridgeProtocol.CoFiX, 'CoFiX');
|
||||
case ERC20BridgeSource.Curve:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Curve, 'Curve');
|
||||
case ERC20BridgeSource.Cream:
|
||||
@@ -99,8 +100,6 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
return encodeBridgeSourceId(BridgeProtocol.CryptoCom, 'CryptoCom');
|
||||
case ERC20BridgeSource.Dodo:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Dodo, 'Dodo');
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Kyber, 'Kyber');
|
||||
case ERC20BridgeSource.LiquidityProvider:
|
||||
// "LiquidityProvider" is too long to encode (17 characters).
|
||||
return encodeBridgeSourceId(BridgeProtocol.Unknown, 'LP');
|
||||
@@ -110,24 +109,16 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
return encodeBridgeSourceId(BridgeProtocol.Mooniswap, 'Mooniswap');
|
||||
case ERC20BridgeSource.MStable:
|
||||
return encodeBridgeSourceId(BridgeProtocol.MStable, 'MStable');
|
||||
case ERC20BridgeSource.Eth2Dai:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Oasis, 'Eth2Dai');
|
||||
case ERC20BridgeSource.Shell:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Shell, 'Shell');
|
||||
case ERC20BridgeSource.SnowSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Curve, 'SnowSwap');
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'SushiSwap');
|
||||
case ERC20BridgeSource.Swerve:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Curve, 'Swerve');
|
||||
case ERC20BridgeSource.Uniswap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Uniswap, 'Uniswap');
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'UniswapV2');
|
||||
case ERC20BridgeSource.DodoV2:
|
||||
return encodeBridgeSourceId(BridgeProtocol.DodoV2, 'DodoV2');
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'Linkswap');
|
||||
case ERC20BridgeSource.PancakeSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'PancakeSwap');
|
||||
case ERC20BridgeSource.PancakeSwapV2:
|
||||
@@ -152,12 +143,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
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');
|
||||
case ERC20BridgeSource.KyberDmm:
|
||||
@@ -172,16 +159,12 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
return encodeBridgeSourceId(BridgeProtocol.CurveV2, 'CurveV2');
|
||||
case ERC20BridgeSource.WaultSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'WaultSwap');
|
||||
case ERC20BridgeSource.Polydex:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'Polydex');
|
||||
case ERC20BridgeSource.FirebirdOneSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Nerve, 'FirebirdOneSwap');
|
||||
case ERC20BridgeSource.Lido:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Lido, 'Lido');
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'ShibaSwap');
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'JetSwap');
|
||||
case ERC20BridgeSource.IronSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Nerve, 'IronSwap');
|
||||
case ERC20BridgeSource.ACryptos:
|
||||
@@ -200,12 +183,32 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'SpookySwap');
|
||||
case ERC20BridgeSource.MorpheusSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'MorpheusSwap');
|
||||
case ERC20BridgeSource.Yoshi:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'Yoshi');
|
||||
case ERC20BridgeSource.AaveV2:
|
||||
return encodeBridgeSourceId(BridgeProtocol.AaveV2, 'AaveV2');
|
||||
case ERC20BridgeSource.Compound:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Compound, 'Compound');
|
||||
case ERC20BridgeSource.Geist:
|
||||
return encodeBridgeSourceId(BridgeProtocol.AaveV2, 'Geist');
|
||||
case ERC20BridgeSource.MobiusMoney:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Nerve, 'MobiusMoney');
|
||||
case ERC20BridgeSource.BiSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'BiSwap');
|
||||
case ERC20BridgeSource.MDex:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'MDex');
|
||||
case ERC20BridgeSource.KnightSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'KnightSwap');
|
||||
case ERC20BridgeSource.GMX:
|
||||
return encodeBridgeSourceId(BridgeProtocol.GMX, 'GMX');
|
||||
case ERC20BridgeSource.Platypus:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Platypus, 'Platypus');
|
||||
case ERC20BridgeSource.MeshSwap:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'MeshSwap');
|
||||
case ERC20BridgeSource.BancorV3:
|
||||
return encodeBridgeSourceId(BridgeProtocol.BancorV3, 'BancorV3');
|
||||
case ERC20BridgeSource.Velodrome:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Velodrome, 'Velodrome');
|
||||
default:
|
||||
throw new Error(AggregationError.NoBridgeForSource);
|
||||
}
|
||||
@@ -229,8 +232,6 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
switch (order.source) {
|
||||
case ERC20BridgeSource.Curve:
|
||||
case ERC20BridgeSource.CurveV2:
|
||||
case ERC20BridgeSource.Swerve:
|
||||
case ERC20BridgeSource.SnowSwap:
|
||||
case ERC20BridgeSource.Nerve:
|
||||
case ERC20BridgeSource.Synapse:
|
||||
case ERC20BridgeSource.Belt:
|
||||
@@ -241,6 +242,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
case ERC20BridgeSource.FirebirdOneSwap:
|
||||
case ERC20BridgeSource.IronSwap:
|
||||
case ERC20BridgeSource.ACryptos:
|
||||
case ERC20BridgeSource.MobiusMoney:
|
||||
const curveFillData = (order as OptimizedMarketBridgeOrder<CurveFillData>).fillData;
|
||||
bridgeData = encoder.encode([
|
||||
curveFillData.pool.poolAddress,
|
||||
@@ -255,9 +257,18 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
bridgeData = encoder.encode([balancerFillData.poolAddress]);
|
||||
break;
|
||||
case ERC20BridgeSource.BalancerV2:
|
||||
{
|
||||
const balancerV2FillData = (order as OptimizedMarketBridgeOrder<BalancerV2BatchSwapFillData>).fillData;
|
||||
bridgeData = encoder.encode([
|
||||
balancerV2FillData.vault,
|
||||
balancerV2FillData.swapSteps,
|
||||
balancerV2FillData.assets,
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case ERC20BridgeSource.Beethovenx:
|
||||
const balancerV2FillData = (order as OptimizedMarketBridgeOrder<BalancerV2FillData>).fillData;
|
||||
const { vault, poolId } = balancerV2FillData;
|
||||
const beethovenFillData = (order as OptimizedMarketBridgeOrder<BalancerV2FillData>).fillData;
|
||||
const { vault, poolId } = beethovenFillData;
|
||||
bridgeData = encoder.encode([vault, poolId]);
|
||||
break;
|
||||
case ERC20BridgeSource.Bancor:
|
||||
@@ -267,34 +278,30 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
case ERC20BridgeSource.PancakeSwap:
|
||||
case ERC20BridgeSource.PancakeSwapV2:
|
||||
case ERC20BridgeSource.BakerySwap:
|
||||
case ERC20BridgeSource.ApeSwap:
|
||||
case ERC20BridgeSource.CafeSwap:
|
||||
case ERC20BridgeSource.CheeseSwap:
|
||||
case ERC20BridgeSource.JulSwap:
|
||||
case ERC20BridgeSource.QuickSwap:
|
||||
case ERC20BridgeSource.ComethSwap:
|
||||
case ERC20BridgeSource.Dfyn:
|
||||
case ERC20BridgeSource.WaultSwap:
|
||||
case ERC20BridgeSource.Polydex:
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
case ERC20BridgeSource.UbeSwap:
|
||||
case ERC20BridgeSource.SpiritSwap:
|
||||
case ERC20BridgeSource.SpookySwap:
|
||||
case ERC20BridgeSource.MorpheusSwap:
|
||||
case ERC20BridgeSource.BiSwap:
|
||||
case ERC20BridgeSource.MDex:
|
||||
case ERC20BridgeSource.KnightSwap:
|
||||
case ERC20BridgeSource.Yoshi:
|
||||
case ERC20BridgeSource.MeshSwap:
|
||||
const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData;
|
||||
bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
|
||||
break;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
const kyberFillData = (order as OptimizedMarketBridgeOrder<KyberFillData>).fillData;
|
||||
bridgeData = encoder.encode([kyberFillData.networkProxy, kyberFillData.hint]);
|
||||
break;
|
||||
case ERC20BridgeSource.Mooniswap:
|
||||
const mooniswapFillData = (order as OptimizedMarketBridgeOrder<MooniswapFillData>).fillData;
|
||||
bridgeData = encoder.encode([mooniswapFillData.poolAddress]);
|
||||
@@ -324,10 +331,6 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
const uniFillData = (order as OptimizedMarketBridgeOrder<GenericRouterFillData>).fillData;
|
||||
bridgeData = encoder.encode([uniFillData.router]);
|
||||
break;
|
||||
case ERC20BridgeSource.Eth2Dai:
|
||||
const oasisFillData = (order as OptimizedMarketBridgeOrder<GenericRouterFillData>).fillData;
|
||||
bridgeData = encoder.encode([oasisFillData.router]);
|
||||
break;
|
||||
case ERC20BridgeSource.MStable:
|
||||
const mStableFillData = (order as OptimizedMarketBridgeOrder<GenericRouterFillData>).fillData;
|
||||
bridgeData = encoder.encode([mStableFillData.router]);
|
||||
@@ -350,7 +353,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
break;
|
||||
case ERC20BridgeSource.Lido:
|
||||
const lidoFillData = (order as OptimizedMarketBridgeOrder<LidoFillData>).fillData;
|
||||
bridgeData = encoder.encode([lidoFillData.stEthTokenAddress]);
|
||||
bridgeData = encoder.encode([lidoFillData.stEthTokenAddress, lidoFillData.wstEthTokenAddress]);
|
||||
break;
|
||||
case ERC20BridgeSource.AaveV2:
|
||||
const aaveFillData = (order as OptimizedMarketBridgeOrder<AaveV2FillData>).fillData;
|
||||
@@ -364,7 +367,31 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
const geistFillData = (order as OptimizedMarketBridgeOrder<GeistFillData>).fillData;
|
||||
bridgeData = encoder.encode([geistFillData.lendingPool, geistFillData.gToken]);
|
||||
break;
|
||||
|
||||
case ERC20BridgeSource.GMX:
|
||||
const gmxFillData = (order as OptimizedMarketBridgeOrder<GMXFillData>).fillData;
|
||||
bridgeData = encoder.encode([
|
||||
gmxFillData.router,
|
||||
gmxFillData.reader,
|
||||
gmxFillData.vault,
|
||||
gmxFillData.tokenAddressPath,
|
||||
]);
|
||||
break;
|
||||
case ERC20BridgeSource.Platypus:
|
||||
const platypusFillData = (order as OptimizedMarketBridgeOrder<PlatypusFillData>).fillData;
|
||||
bridgeData = encoder.encode([
|
||||
platypusFillData.router,
|
||||
platypusFillData.pool,
|
||||
platypusFillData.tokenAddressPath,
|
||||
]);
|
||||
break;
|
||||
case ERC20BridgeSource.BancorV3:
|
||||
const bancorV3FillData = (order as OptimizedMarketBridgeOrder<BancorFillData>).fillData;
|
||||
bridgeData = encoder.encode([bancorV3FillData.networkAddress, bancorV3FillData.path]);
|
||||
break;
|
||||
case ERC20BridgeSource.Velodrome:
|
||||
const velodromeFillData = (order as OptimizedMarketBridgeOrder<VelodromeFillData>).fillData;
|
||||
bridgeData = encoder.encode([velodromeFillData.router, velodromeFillData.stable]);
|
||||
break;
|
||||
default:
|
||||
throw new Error(AggregationError.NoBridgeForSource);
|
||||
}
|
||||
@@ -450,6 +477,8 @@ const balancerV2Encoder = AbiEncoder.create([
|
||||
]);
|
||||
const routerAddressPathEncoder = AbiEncoder.create('(address,address[])');
|
||||
const tokenAddressEncoder = AbiEncoder.create([{ name: 'tokenAddress', type: 'address' }]);
|
||||
const gmxAddressPathEncoder = AbiEncoder.create('(address,address,address,address[])');
|
||||
const platypusAddressPathEncoder = AbiEncoder.create('(address,address[],address[])');
|
||||
|
||||
export const BRIDGE_ENCODERS: {
|
||||
[key in Exclude<
|
||||
@@ -461,10 +490,6 @@ export const BRIDGE_ENCODERS: {
|
||||
{ name: 'provider', type: 'address' },
|
||||
{ name: 'data', type: 'bytes' },
|
||||
]),
|
||||
[ERC20BridgeSource.Kyber]: AbiEncoder.create([
|
||||
{ name: 'kyberNetworkProxy', type: 'address' },
|
||||
{ name: 'hint', type: 'bytes' },
|
||||
]),
|
||||
[ERC20BridgeSource.Dodo]: AbiEncoder.create([
|
||||
{ name: 'helper', type: 'address' },
|
||||
{ name: 'poolAddress', type: 'address' },
|
||||
@@ -477,8 +502,6 @@ export const BRIDGE_ENCODERS: {
|
||||
// Curve like
|
||||
[ERC20BridgeSource.Curve]: curveEncoder,
|
||||
[ERC20BridgeSource.CurveV2]: curveEncoder,
|
||||
[ERC20BridgeSource.Swerve]: curveEncoder,
|
||||
[ERC20BridgeSource.SnowSwap]: curveEncoder,
|
||||
[ERC20BridgeSource.Nerve]: curveEncoder,
|
||||
[ERC20BridgeSource.Synapse]: curveEncoder,
|
||||
[ERC20BridgeSource.Belt]: curveEncoder,
|
||||
@@ -489,18 +512,27 @@ export const BRIDGE_ENCODERS: {
|
||||
[ERC20BridgeSource.FirebirdOneSwap]: curveEncoder,
|
||||
[ERC20BridgeSource.IronSwap]: curveEncoder,
|
||||
[ERC20BridgeSource.ACryptos]: curveEncoder,
|
||||
[ERC20BridgeSource.MobiusMoney]: curveEncoder,
|
||||
// UniswapV2 like, (router, address[])
|
||||
[ERC20BridgeSource.Bancor]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.BancorV3]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Linkswap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.ShibaSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Pangolin]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.TraderJoe]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.SpiritSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.SpookySwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.MorpheusSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.BiSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.MDex]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.KnightSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Yoshi]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.MeshSwap]: routerAddressPathEncoder,
|
||||
// Avalanche
|
||||
[ERC20BridgeSource.GMX]: gmxAddressPathEncoder,
|
||||
[ERC20BridgeSource.Platypus]: platypusAddressPathEncoder,
|
||||
// Celo
|
||||
[ERC20BridgeSource.UbeSwap]: routerAddressPathEncoder,
|
||||
// BSC
|
||||
@@ -508,38 +540,48 @@ export const BRIDGE_ENCODERS: {
|
||||
[ERC20BridgeSource.PancakeSwapV2]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.BakerySwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.ApeSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.CafeSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.CheeseSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.JulSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.WaultSwap]: routerAddressPathEncoder,
|
||||
// Polygon
|
||||
[ERC20BridgeSource.QuickSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.ComethSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Dfyn]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Polydex]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.JetSwap]: routerAddressPathEncoder,
|
||||
// Generic pools
|
||||
[ERC20BridgeSource.Shell]: poolEncoder,
|
||||
[ERC20BridgeSource.Component]: poolEncoder,
|
||||
[ERC20BridgeSource.Mooniswap]: poolEncoder,
|
||||
[ERC20BridgeSource.Eth2Dai]: poolEncoder,
|
||||
[ERC20BridgeSource.MStable]: poolEncoder,
|
||||
[ERC20BridgeSource.Balancer]: poolEncoder,
|
||||
[ERC20BridgeSource.Cream]: poolEncoder,
|
||||
[ERC20BridgeSource.Uniswap]: poolEncoder,
|
||||
// Custom integrations
|
||||
[ERC20BridgeSource.MakerPsm]: makerPsmEncoder,
|
||||
[ERC20BridgeSource.BalancerV2]: balancerV2Encoder,
|
||||
[ERC20BridgeSource.BalancerV2]: AbiEncoder.create([
|
||||
{ name: 'vault', type: 'address' },
|
||||
{
|
||||
name: 'swapSteps',
|
||||
type: 'tuple[]',
|
||||
components: [
|
||||
{ name: 'poolId', type: 'bytes32' },
|
||||
{ name: 'assetInIndex', type: 'uint256' },
|
||||
{ name: 'assetOutIndex', type: 'uint256' },
|
||||
{ name: 'amount', type: 'uint256' },
|
||||
{ name: 'userData', type: 'bytes' },
|
||||
],
|
||||
},
|
||||
{ name: 'assets', type: 'address[]' },
|
||||
]),
|
||||
[ERC20BridgeSource.Beethovenx]: balancerV2Encoder,
|
||||
[ERC20BridgeSource.UniswapV3]: AbiEncoder.create([
|
||||
{ name: 'router', type: 'address' },
|
||||
{ name: 'path', type: 'bytes' },
|
||||
]),
|
||||
[ERC20BridgeSource.KyberDmm]: AbiEncoder.create('(address,address[],address[])'),
|
||||
[ERC20BridgeSource.Lido]: AbiEncoder.create('(address)'),
|
||||
[ERC20BridgeSource.Lido]: AbiEncoder.create('(address,address)'),
|
||||
[ERC20BridgeSource.AaveV2]: AbiEncoder.create('(address,address)'),
|
||||
[ERC20BridgeSource.Compound]: AbiEncoder.create('(address)'),
|
||||
[ERC20BridgeSource.Geist]: AbiEncoder.create('(address,address)'),
|
||||
[ERC20BridgeSource.Velodrome]: AbiEncoder.create('(address,bool)'),
|
||||
};
|
||||
|
||||
function getFillTokenAmounts(fill: CollapsedFill, side: MarketOperation): [BigNumber, BigNumber] {
|
||||
|
@@ -122,17 +122,8 @@ export class Path {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
// If there are contiguous bridge orders, we can batch them together.
|
||||
// TODO jacob pretty sure this is from DFB and we can remove
|
||||
const contiguousBridgeFills = [collapsedFills[i]];
|
||||
for (let j = i + 1; j < collapsedFills.length; ++j) {
|
||||
if (collapsedFills[j].source === ERC20BridgeSource.Native) {
|
||||
break;
|
||||
}
|
||||
contiguousBridgeFills.push(collapsedFills[j]);
|
||||
}
|
||||
|
||||
this.orders.push(createBridgeOrder(contiguousBridgeFills[0], makerToken, takerToken, opts.side));
|
||||
this.orders.push(createBridgeOrder(collapsedFills[i], makerToken, takerToken, opts.side));
|
||||
i += 1;
|
||||
}
|
||||
return this as CollapsedPath;
|
||||
|
@@ -76,7 +76,8 @@ function findRoutesAndCreateOptimalPath(
|
||||
opts: PathPenaltyOpts,
|
||||
fees: FeeSchedule,
|
||||
neonRouterNumSamples: number,
|
||||
): Path | undefined {
|
||||
vipSourcesSet: Set<ERC20BridgeSource>,
|
||||
): { allSourcesPath: Path | undefined; vipSourcesPath: Path | undefined } | undefined {
|
||||
// Currently the rust router is unable to handle 1 base unit sized quotes and will error out
|
||||
// To avoid flooding the logs with these errors we just return an insufficient liquidity error
|
||||
// which is how the JS router handles these quotes today
|
||||
@@ -94,6 +95,127 @@ function findRoutesAndCreateOptimalPath(
|
||||
return fills[0];
|
||||
};
|
||||
|
||||
const createPathFromStrategy = (sourcesRustRoute: Float64Array, sourcesOutputAmounts: Float64Array) => {
|
||||
const routesAndSamplesAndOutputs = _.zip(
|
||||
sourcesRustRoute,
|
||||
samplesAndNativeOrdersWithResults,
|
||||
sourcesOutputAmounts,
|
||||
sampleSourcePathIds,
|
||||
);
|
||||
const adjustedFills: Fill[] = [];
|
||||
const totalRoutedAmount = BigNumber.sum(...sourcesRustRoute);
|
||||
|
||||
const scale = input.dividedBy(totalRoutedAmount);
|
||||
for (const [
|
||||
routeInput,
|
||||
routeSamplesAndNativeOrders,
|
||||
outputAmount,
|
||||
sourcePathId,
|
||||
] of routesAndSamplesAndOutputs) {
|
||||
if (!Number.isFinite(outputAmount)) {
|
||||
DEFAULT_WARNING_LOGGER(rustArgs, `neon-router: invalid route outputAmount ${outputAmount}`);
|
||||
return undefined;
|
||||
}
|
||||
if (!routeInput || !routeSamplesAndNativeOrders || !outputAmount) {
|
||||
continue;
|
||||
}
|
||||
// TODO(kimpers): [TKR-241] amounts are sometimes clipped in the router due to precision loss for number/f64
|
||||
// we can work around it by scaling it and rounding up. However now we end up with a total amount of a couple base units too much
|
||||
const rustInputAdjusted = BigNumber.min(
|
||||
new BigNumber(routeInput).multipliedBy(scale).integerValue(BigNumber.ROUND_CEIL),
|
||||
input,
|
||||
);
|
||||
|
||||
const current = routeSamplesAndNativeOrders[routeSamplesAndNativeOrders.length - 1];
|
||||
if (!isDexSample(current)) {
|
||||
const nativeFill = nativeOrdersToFills(
|
||||
side,
|
||||
[current],
|
||||
rustInputAdjusted,
|
||||
opts.outputAmountPerEth,
|
||||
opts.inputAmountPerEth,
|
||||
fees,
|
||||
false,
|
||||
)[0] as Fill | undefined;
|
||||
// Note: If the order has an adjusted rate of less than or equal to 0 it will be skipped
|
||||
// and nativeFill will be `undefined`
|
||||
if (nativeFill) {
|
||||
// NOTE: For Limit/RFQ orders we are done here. No need to scale output
|
||||
adjustedFills.push({ ...nativeFill, sourcePathId: sourcePathId ?? hexUtils.random() });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: For DexSamples only
|
||||
let fill = createFill(current);
|
||||
if (!fill) {
|
||||
continue;
|
||||
}
|
||||
const routeSamples = routeSamplesAndNativeOrders as Array<DexSample<FillData>>;
|
||||
// Descend to approach a closer fill for fillData which may not be consistent
|
||||
// throughout the path (UniswapV3) and for a closer guesstimate at
|
||||
// gas used
|
||||
|
||||
assert.assert(routeSamples.length >= 1, 'Found no sample to use for source');
|
||||
for (let k = routeSamples.length - 1; k >= 0; k--) {
|
||||
if (k === 0) {
|
||||
fill = createFill(routeSamples[0]) ?? fill;
|
||||
}
|
||||
if (rustInputAdjusted.isGreaterThan(routeSamples[k].input)) {
|
||||
const left = routeSamples[k];
|
||||
const right = routeSamples[k + 1];
|
||||
if (left && right) {
|
||||
fill =
|
||||
createFill({
|
||||
...right, // default to the greater (for gas used)
|
||||
input: rustInputAdjusted,
|
||||
output: new BigNumber(outputAmount),
|
||||
}) ?? fill;
|
||||
} else {
|
||||
assert.assert(Boolean(left || right), 'No valid sample to use');
|
||||
fill = createFill(left || right) ?? fill;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(kimpers): remove once we have solved the rounding/precision loss issues in the Rust router
|
||||
const maxSampledOutput = BigNumber.max(...routeSamples.map(s => s.output));
|
||||
// Scale output by scale factor but never go above the largest sample in sell quotes (unknown liquidity) or below 1 base unit (unfillable)
|
||||
const scaleOutput = (output: BigNumber) => {
|
||||
// Don't try to scale 0 output as it will be clamped to 1
|
||||
if (output.eq(ZERO_AMOUNT)) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const scaled = output
|
||||
.times(scale)
|
||||
.decimalPlaces(0, side === MarketOperation.Sell ? BigNumber.ROUND_FLOOR : BigNumber.ROUND_CEIL);
|
||||
const capped = MarketOperation.Sell ? BigNumber.min(scaled, maxSampledOutput) : scaled;
|
||||
|
||||
return BigNumber.max(capped, 1);
|
||||
};
|
||||
|
||||
adjustedFills.push({
|
||||
...fill,
|
||||
input: rustInputAdjusted,
|
||||
output: scaleOutput(fill.output),
|
||||
adjustedOutput: scaleOutput(fill.adjustedOutput),
|
||||
index: 0,
|
||||
parent: undefined,
|
||||
sourcePathId: sourcePathId ?? hexUtils.random(),
|
||||
});
|
||||
}
|
||||
|
||||
if (adjustedFills.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const pathFromRustInputs = Path.create(side, adjustedFills, input, opts);
|
||||
|
||||
return pathFromRustInputs;
|
||||
};
|
||||
|
||||
const samplesAndNativeOrdersWithResults: Array<DexSample[] | NativeOrderWithFillableAmounts[]> = [];
|
||||
const serializedPaths: SerializedPath[] = [];
|
||||
const sampleSourcePathIds: string[] = [];
|
||||
@@ -105,8 +227,9 @@ function findRoutesAndCreateOptimalPath(
|
||||
const sourcePathId = hexUtils.random();
|
||||
const singleSourceSamplesWithOutput = [...singleSourceSamples];
|
||||
for (let i = singleSourceSamples.length - 1; i >= 0; i--) {
|
||||
if (singleSourceSamples[i].output.isZero()) {
|
||||
// Remove trailing 0 output samples
|
||||
const currentOutput = singleSourceSamples[i].output;
|
||||
if (currentOutput.isZero() || !currentOutput.isFinite()) {
|
||||
// Remove trailing 0/invalid output samples
|
||||
singleSourceSamplesWithOutput.pop();
|
||||
} else {
|
||||
break;
|
||||
@@ -136,6 +259,7 @@ function findRoutesAndCreateOptimalPath(
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
outputFees: [],
|
||||
isVip: vipSourcesSet.has(singleSourceSamplesWithOutput[0]?.source),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -194,6 +318,7 @@ function findRoutesAndCreateOptimalPath(
|
||||
inputs,
|
||||
outputs,
|
||||
outputFees,
|
||||
isVip: true,
|
||||
};
|
||||
|
||||
samplesAndNativeOrdersWithResults.push([nativeOrder]);
|
||||
@@ -212,129 +337,42 @@ function findRoutesAndCreateOptimalPath(
|
||||
};
|
||||
|
||||
const allSourcesRustRoute = new Float64Array(rustArgs.pathsIn.length);
|
||||
const strategySourcesOutputAmounts = new Float64Array(rustArgs.pathsIn.length);
|
||||
route(rustArgs, allSourcesRustRoute, strategySourcesOutputAmounts, neonRouterNumSamples);
|
||||
const allSourcesOutputAmounts = new Float64Array(rustArgs.pathsIn.length);
|
||||
const vipSourcesRustRoute = new Float64Array(rustArgs.pathsIn.length);
|
||||
const vipSourcesOutputAmounts = new Float64Array(rustArgs.pathsIn.length);
|
||||
|
||||
route(
|
||||
rustArgs,
|
||||
allSourcesRustRoute,
|
||||
allSourcesOutputAmounts,
|
||||
vipSourcesRustRoute,
|
||||
vipSourcesOutputAmounts,
|
||||
neonRouterNumSamples,
|
||||
);
|
||||
assert.assert(
|
||||
rustArgs.pathsIn.length === allSourcesRustRoute.length,
|
||||
'different number of sources in the Router output than the input',
|
||||
);
|
||||
assert.assert(
|
||||
rustArgs.pathsIn.length === strategySourcesOutputAmounts.length,
|
||||
rustArgs.pathsIn.length === allSourcesOutputAmounts.length,
|
||||
'different number of sources in the Router output amounts results than the input',
|
||||
);
|
||||
assert.assert(
|
||||
rustArgs.pathsIn.length === vipSourcesRustRoute.length,
|
||||
'different number of sources in the Router output than the input',
|
||||
);
|
||||
assert.assert(
|
||||
rustArgs.pathsIn.length === vipSourcesOutputAmounts.length,
|
||||
'different number of sources in the Router output amounts results than the input',
|
||||
);
|
||||
|
||||
const routesAndSamplesAndOutputs = _.zip(
|
||||
allSourcesRustRoute,
|
||||
samplesAndNativeOrdersWithResults,
|
||||
strategySourcesOutputAmounts,
|
||||
sampleSourcePathIds,
|
||||
);
|
||||
const adjustedFills: Fill[] = [];
|
||||
const totalRoutedAmount = BigNumber.sum(...allSourcesRustRoute);
|
||||
const allSourcesPath = createPathFromStrategy(allSourcesRustRoute, allSourcesOutputAmounts);
|
||||
const vipSourcesPath = createPathFromStrategy(vipSourcesRustRoute, vipSourcesOutputAmounts);
|
||||
|
||||
const scale = input.dividedBy(totalRoutedAmount);
|
||||
for (const [routeInput, routeSamplesAndNativeOrders, outputAmount, sourcePathId] of routesAndSamplesAndOutputs) {
|
||||
if (!Number.isFinite(outputAmount)) {
|
||||
DEFAULT_WARNING_LOGGER(rustArgs, `neon-router: invalid route outputAmount ${outputAmount}`);
|
||||
return undefined;
|
||||
}
|
||||
if (!routeInput || !routeSamplesAndNativeOrders || !outputAmount) {
|
||||
continue;
|
||||
}
|
||||
// TODO(kimpers): [TKR-241] amounts are sometimes clipped in the router due to precision loss for number/f64
|
||||
// we can work around it by scaling it and rounding up. However now we end up with a total amount of a couple base units too much
|
||||
const rustInputAdjusted = BigNumber.min(
|
||||
new BigNumber(routeInput).multipliedBy(scale).integerValue(BigNumber.ROUND_CEIL),
|
||||
input,
|
||||
);
|
||||
|
||||
const current = routeSamplesAndNativeOrders[routeSamplesAndNativeOrders.length - 1];
|
||||
if (!isDexSample(current)) {
|
||||
const nativeFill = nativeOrdersToFills(
|
||||
side,
|
||||
[current],
|
||||
rustInputAdjusted,
|
||||
opts.outputAmountPerEth,
|
||||
opts.inputAmountPerEth,
|
||||
fees,
|
||||
false,
|
||||
)[0] as Fill | undefined;
|
||||
// Note: If the order has an adjusted rate of less than or equal to 0 it will be skipped
|
||||
// and nativeFill will be `undefined`
|
||||
if (nativeFill) {
|
||||
// NOTE: For Limit/RFQ orders we are done here. No need to scale output
|
||||
adjustedFills.push({ ...nativeFill, sourcePathId: sourcePathId ?? hexUtils.random() });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: For DexSamples only
|
||||
let fill = createFill(current);
|
||||
if (!fill) {
|
||||
continue;
|
||||
}
|
||||
const routeSamples = routeSamplesAndNativeOrders as Array<DexSample<FillData>>;
|
||||
// Descend to approach a closer fill for fillData which may not be consistent
|
||||
// throughout the path (UniswapV3) and for a closer guesstimate at
|
||||
// gas used
|
||||
|
||||
assert.assert(routeSamples.length >= 1, 'Found no sample to use for source');
|
||||
for (let k = routeSamples.length - 1; k >= 0; k--) {
|
||||
if (k === 0) {
|
||||
fill = createFill(routeSamples[0]) ?? fill;
|
||||
}
|
||||
if (rustInputAdjusted.isGreaterThan(routeSamples[k].input)) {
|
||||
const left = routeSamples[k];
|
||||
const right = routeSamples[k + 1];
|
||||
if (left && right) {
|
||||
fill =
|
||||
createFill({
|
||||
...right, // default to the greater (for gas used)
|
||||
input: rustInputAdjusted,
|
||||
output: new BigNumber(outputAmount),
|
||||
}) ?? fill;
|
||||
} else {
|
||||
assert.assert(Boolean(left || right), 'No valid sample to use');
|
||||
fill = createFill(left || right) ?? fill;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(kimpers): remove once we have solved the rounding/precision loss issues in the Rust router
|
||||
const maxSampledOutput = BigNumber.max(...routeSamples.map(s => s.output));
|
||||
// Scale output by scale factor but never go above the largest sample (unknown liquidity) or below 1 base unit (unfillable)
|
||||
const scaleOutput = (output: BigNumber) => {
|
||||
// Don't try to scale 0 output as it will be clamped to 1
|
||||
if (output.eq(ZERO_AMOUNT)) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const scaled = output
|
||||
.times(scale)
|
||||
.decimalPlaces(0, side === MarketOperation.Sell ? BigNumber.ROUND_FLOOR : BigNumber.ROUND_CEIL);
|
||||
|
||||
return BigNumber.max(BigNumber.min(scaled, maxSampledOutput), 1);
|
||||
};
|
||||
|
||||
adjustedFills.push({
|
||||
...fill,
|
||||
input: rustInputAdjusted,
|
||||
output: scaleOutput(fill.output),
|
||||
adjustedOutput: scaleOutput(fill.adjustedOutput),
|
||||
index: 0,
|
||||
parent: undefined,
|
||||
sourcePathId: sourcePathId ?? hexUtils.random(),
|
||||
});
|
||||
}
|
||||
|
||||
if (adjustedFills.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const pathFromRustInputs = Path.create(side, adjustedFills, input, opts);
|
||||
|
||||
return pathFromRustInputs;
|
||||
return {
|
||||
allSourcesPath,
|
||||
vipSourcesPath,
|
||||
};
|
||||
}
|
||||
|
||||
export function findOptimalRustPathFromSamples(
|
||||
@@ -348,9 +386,18 @@ export function findOptimalRustPathFromSamples(
|
||||
neonRouterNumSamples: number,
|
||||
samplerMetrics?: SamplerMetrics,
|
||||
): Path | undefined {
|
||||
const beforeAllTimeMs = performance.now();
|
||||
let beforeTimeMs = performance.now();
|
||||
const allSourcesPath = findRoutesAndCreateOptimalPath(
|
||||
const beforeTimeMs = performance.now();
|
||||
const sendMetrics = () => {
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
samplerMetrics &&
|
||||
samplerMetrics.logRouterDetails({
|
||||
router: 'neon-router',
|
||||
type: 'total',
|
||||
timingMs: performance.now() - beforeTimeMs,
|
||||
});
|
||||
};
|
||||
const vipSourcesSet = new Set(VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID[chainId]);
|
||||
const paths = findRoutesAndCreateOptimalPath(
|
||||
side,
|
||||
samples,
|
||||
nativeOrders,
|
||||
@@ -358,58 +405,22 @@ export function findOptimalRustPathFromSamples(
|
||||
opts,
|
||||
fees,
|
||||
neonRouterNumSamples,
|
||||
vipSourcesSet,
|
||||
);
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
samplerMetrics &&
|
||||
samplerMetrics.logRouterDetails({
|
||||
router: 'neon-router',
|
||||
type: 'all',
|
||||
timingMs: performance.now() - beforeTimeMs,
|
||||
});
|
||||
if (!allSourcesPath) {
|
||||
|
||||
if (!paths) {
|
||||
sendMetrics();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const vipSources = VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID[chainId];
|
||||
const { allSourcesPath, vipSourcesPath } = paths;
|
||||
|
||||
// HACK(kimpers): The Rust router currently doesn't account for VIP sources correctly
|
||||
// we need to try to route them in isolation and compare with the results all sources
|
||||
if (vipSources.length > 0) {
|
||||
beforeTimeMs = performance.now();
|
||||
const vipSourcesSet = new Set(vipSources);
|
||||
const vipSourcesSamples = samples.filter(s => s[0] && vipSourcesSet.has(s[0].source));
|
||||
|
||||
if (vipSourcesSamples.length > 0) {
|
||||
const vipSourcesPath = findRoutesAndCreateOptimalPath(
|
||||
side,
|
||||
vipSourcesSamples,
|
||||
[],
|
||||
input,
|
||||
opts,
|
||||
fees,
|
||||
neonRouterNumSamples,
|
||||
);
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
samplerMetrics &&
|
||||
samplerMetrics.logRouterDetails({
|
||||
router: 'neon-router',
|
||||
type: 'vip',
|
||||
timingMs: performance.now() - beforeTimeMs,
|
||||
});
|
||||
|
||||
if (vipSourcesPath?.isBetterThan(allSourcesPath)) {
|
||||
return vipSourcesPath;
|
||||
}
|
||||
}
|
||||
if (!allSourcesPath || vipSourcesPath?.isBetterThan(allSourcesPath)) {
|
||||
sendMetrics();
|
||||
return vipSourcesPath;
|
||||
}
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
samplerMetrics &&
|
||||
samplerMetrics.logRouterDetails({
|
||||
router: 'neon-router',
|
||||
type: 'total',
|
||||
timingMs: performance.now() - beforeAllTimeMs,
|
||||
});
|
||||
|
||||
sendMetrics();
|
||||
return allSourcesPath;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { getPoolsWithTokens, parsePoolData } from '@balancer-labs/sor';
|
||||
import { Pool } from '@balancer-labs/sor/dist/types';
|
||||
import { getPoolsWithTokens, parsePoolData } from 'balancer-labs-sor-v1';
|
||||
import { Pool } from 'balancer-labs-sor-v1/dist/types';
|
||||
import { gql, request } from 'graphql-request';
|
||||
|
||||
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_SUBGRAPH_URL, BALANCER_TOP_POOLS_FETCHED } from '../constants';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
// import { parsePoolData } from '@balancer-labs'; // TODO - upgrade to v2
|
||||
import { Pool } from '@balancer-labs/sor/dist/types';
|
||||
import { Pool } from 'balancer-labs-sor-v1/dist/types';
|
||||
import { gql, request } from 'graphql-request';
|
||||
|
||||
import { DEFAULT_WARNING_LOGGER } from '../../../constants';
|
||||
@@ -51,7 +51,7 @@ export class BalancerV2PoolsCache extends PoolsCache {
|
||||
|
||||
constructor(
|
||||
chainId: ChainId,
|
||||
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId],
|
||||
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId]!,
|
||||
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
|
||||
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
|
||||
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
|
||||
|
@@ -0,0 +1,190 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import {
|
||||
BalancerSDK,
|
||||
BalancerSdkConfig,
|
||||
formatSequence,
|
||||
getTokenAddressesForSwap,
|
||||
NewPath,
|
||||
parseToPoolsDict,
|
||||
PoolDictionary,
|
||||
RouteProposer,
|
||||
SwapTypes,
|
||||
} from '@balancer-labs/sdk';
|
||||
|
||||
import { DEFAULT_WARNING_LOGGER } from '../../../constants';
|
||||
import { LogFunction } from '../../../types';
|
||||
import { BALANCER_V2_SUBGRAPH_URL_BY_CHAIN, ONE_SECOND_MS } from '../constants';
|
||||
import { BalancerSwapInfo, BalancerSwaps } from '../types';
|
||||
|
||||
import { CacheValue, EMPTY_BALANCER_SWAPS, SwapInfoCache } from './pair_swaps_cache';
|
||||
import { SubgraphPoolDataService } from './sgPoolDataService';
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const ONE_DAY_MS = 24 * 60 * 60 * ONE_SECOND_MS;
|
||||
|
||||
export interface BalancerPoolResponse {
|
||||
poolType: string;
|
||||
id: string;
|
||||
tokens: Array<{ address: string }>;
|
||||
tokensList: string[];
|
||||
}
|
||||
|
||||
export class BalancerV2SwapInfoCache extends SwapInfoCache {
|
||||
private static readonly _MAX_POOLS_PER_PATH = 4;
|
||||
private static readonly _MAX_CANDIDATE_PATHS_PER_PAIR = 2;
|
||||
private readonly _routeProposer: RouteProposer;
|
||||
private readonly _poolDataService: SubgraphPoolDataService;
|
||||
|
||||
constructor(
|
||||
chainId: ChainId,
|
||||
subgraphUrl: string | null = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId],
|
||||
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
|
||||
cache: { [key: string]: CacheValue } = {},
|
||||
) {
|
||||
super(cache);
|
||||
const config: BalancerSdkConfig = {
|
||||
network: chainId as number, // wtf TS
|
||||
rpcUrl: '', // Not actually used by SDK for this.
|
||||
};
|
||||
const balancerSdk = new BalancerSDK(config);
|
||||
// The RouteProposer finds paths between a token pair using direct/multihop/linearPool routes
|
||||
this._routeProposer = balancerSdk.sor.routeProposer;
|
||||
// Uses Subgraph to retrieve up to date pool data required for routeProposer
|
||||
this._poolDataService = new SubgraphPoolDataService({
|
||||
chainId,
|
||||
subgraphUrl,
|
||||
});
|
||||
void this._loadTopPoolsAsync();
|
||||
// Reload the top pools every 12 hours
|
||||
setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2);
|
||||
}
|
||||
|
||||
protected async _loadTopPoolsAsync(): Promise<void> {
|
||||
const fromToSwapInfo: {
|
||||
[from: string]: { [to: string]: BalancerSwaps };
|
||||
} = {};
|
||||
|
||||
// Retrieve pool data from Subgraph
|
||||
const pools = await this._poolDataService.getPools();
|
||||
// timestamp is used for Element pools
|
||||
const timestamp = Math.floor(Date.now() / ONE_SECOND_MS);
|
||||
const poolsDict = parseToPoolsDict(pools, timestamp);
|
||||
|
||||
for (const pool of pools) {
|
||||
const { tokensList } = pool;
|
||||
// tslint:disable-next-line: await-promise
|
||||
await null; // This loop can be CPU heavy so yield to event loop.
|
||||
for (const from of tokensList) {
|
||||
for (const to of tokensList.filter(t => t.toLowerCase() !== from.toLowerCase())) {
|
||||
fromToSwapInfo[from] = fromToSwapInfo[from] || {};
|
||||
// If a record for pair already exists skip as all paths alreay found
|
||||
if (fromToSwapInfo[from][to]) {
|
||||
continue;
|
||||
} else {
|
||||
try {
|
||||
const expiresAt = Date.now() + this._cacheTimeMs;
|
||||
// Retrieve swap steps and assets for a token pair
|
||||
// This only needs to be called once per pair as all paths will be created from single call
|
||||
const pairSwapInfo = this._getPoolPairSwapInfo(poolsDict, from, to);
|
||||
fromToSwapInfo[from][to] = pairSwapInfo;
|
||||
this._cacheSwapInfoForPair(from, to, fromToSwapInfo[from][to], expiresAt);
|
||||
} catch (err) {
|
||||
this._warningLogger(err, `Failed to load Balancer V2 top pools`);
|
||||
// soldier on
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will retrieve fresh pair and path data from Subgraph and return and array of swap info for pair..
|
||||
* @param takerToken Address of takerToken.
|
||||
* @param makerToken Address of makerToken.
|
||||
* @returns Swap data for pair consisting of assets and swap steps for ExactIn and ExactOut swap types.
|
||||
*/
|
||||
protected async _fetchSwapInfoForPairAsync(takerToken: string, makerToken: string): Promise<BalancerSwaps> {
|
||||
try {
|
||||
// retrieve up to date pools from SG
|
||||
const pools = await this._poolDataService.getPools();
|
||||
|
||||
// timestamp is used for Element pools
|
||||
const timestamp = Math.floor(Date.now() / ONE_SECOND_MS);
|
||||
const poolDictionary = parseToPoolsDict(pools, timestamp);
|
||||
return this._getPoolPairSwapInfo(poolDictionary, takerToken, makerToken);
|
||||
} catch (e) {
|
||||
return EMPTY_BALANCER_SWAPS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses pool data from provided dictionary to find top swap paths for token pair.
|
||||
* @param pools Dictionary of pool data.
|
||||
* @param takerToken Address of taker token.
|
||||
* @param makerToken Address of maker token.
|
||||
* @returns Swap data for pair consisting of assets and swap steps for ExactIn and ExactOut swap types.
|
||||
*/
|
||||
private _getPoolPairSwapInfo(pools: PoolDictionary, takerToken: string, makerToken: string): BalancerSwaps {
|
||||
/*
|
||||
Uses Balancer SDK to construct available paths for pair.
|
||||
Paths can be direct, i.e. both tokens are in same pool or multihop.
|
||||
Will also create paths for the new Balancer Linear pools.
|
||||
These are returned in order of available liquidity which is useful for filtering.
|
||||
*/
|
||||
const paths = this._routeProposer.getCandidatePathsFromDict(
|
||||
takerToken,
|
||||
makerToken,
|
||||
SwapTypes.SwapExactIn,
|
||||
pools,
|
||||
BalancerV2SwapInfoCache._MAX_POOLS_PER_PATH,
|
||||
);
|
||||
|
||||
if (paths.length === 0) {
|
||||
return EMPTY_BALANCER_SWAPS;
|
||||
}
|
||||
|
||||
// Convert paths data to swap information suitable for queryBatchSwap. Only use top 2 liquid paths
|
||||
return formatSwaps(paths.slice(0, BalancerV2SwapInfoCache._MAX_CANDIDATE_PATHS_PER_PAIR));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of Balancer paths, returns swap information that can be passed to queryBatchSwap.
|
||||
* @param paths Array of Balancer paths.
|
||||
* @returns Formatted swap data consisting of assets and swap steps for ExactIn and ExactOut swap types.
|
||||
*/
|
||||
function formatSwaps(paths: NewPath[]): BalancerSwaps {
|
||||
const formattedSwapsExactIn: BalancerSwapInfo[] = [];
|
||||
const formattedSwapsExactOut: BalancerSwapInfo[] = [];
|
||||
let assets: string[];
|
||||
paths.forEach(path => {
|
||||
// Add a swap amount for each swap so we can use formatSequence. (This will be overwritten with actual amount during query)
|
||||
path.swaps.forEach(s => (s.swapAmount = '0'));
|
||||
const tokenAddresses = getTokenAddressesForSwap(path.swaps);
|
||||
// Formats for both ExactIn and ExactOut swap types
|
||||
const swapsExactIn = formatSequence(SwapTypes.SwapExactIn, path.swaps, tokenAddresses);
|
||||
const swapsExactOut = formatSequence(SwapTypes.SwapExactOut, path.swaps, tokenAddresses);
|
||||
assets = tokenAddresses;
|
||||
formattedSwapsExactIn.push({
|
||||
assets,
|
||||
swapSteps: swapsExactIn.map(s => ({
|
||||
...s,
|
||||
amount: new BigNumber(s.amount),
|
||||
})),
|
||||
});
|
||||
formattedSwapsExactOut.push({
|
||||
assets,
|
||||
swapSteps: swapsExactOut.map(s => ({
|
||||
...s,
|
||||
amount: new BigNumber(s.amount),
|
||||
})),
|
||||
});
|
||||
});
|
||||
const formattedSwaps: BalancerSwaps = {
|
||||
swapInfoExactIn: formattedSwapsExactIn,
|
||||
swapInfoExactOut: formattedSwapsExactOut,
|
||||
};
|
||||
return formattedSwaps;
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
import { Pool } from '@balancer-labs/sor/dist/types';
|
||||
import { Pool } from 'balancer-labs-sor-v1/dist/types';
|
||||
import { getPoolsWithTokens, parsePoolData } from 'cream-sor';
|
||||
|
||||
import { BALANCER_MAX_POOLS_FETCHED } from '../constants';
|
||||
|
@@ -0,0 +1,91 @@
|
||||
import { BalancerSwaps } from '../types';
|
||||
|
||||
import { ONE_HOUR_IN_SECONDS, ONE_SECOND_MS } from '../constants';
|
||||
|
||||
export interface CacheValue {
|
||||
expiresAt: number;
|
||||
balancerSwaps: BalancerSwaps;
|
||||
}
|
||||
|
||||
// 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 = ONE_SECOND_MS;
|
||||
export const EMPTY_BALANCER_SWAPS = { swapInfoExactIn: [], swapInfoExactOut: [] };
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
|
||||
/**
|
||||
* Caches SwapInfo for a pair of tokens.
|
||||
* SwapInfo includes swap steps and asset information for those swap steps.
|
||||
*/
|
||||
export abstract class SwapInfoCache {
|
||||
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<BalancerSwaps> {
|
||||
const timeout = new Promise<BalancerSwaps>(resolve => setTimeout(resolve, timeoutMs, []));
|
||||
return Promise.race([this._getAndSaveFreshSwapInfoForPairAsync(takerToken, makerToken), timeout]);
|
||||
}
|
||||
|
||||
public getCachedSwapInfoForPair(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
ignoreExpired: boolean = true,
|
||||
): BalancerSwaps | undefined {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
const value = this._cache[key];
|
||||
if (ignoreExpired) {
|
||||
return value === undefined ? EMPTY_BALANCER_SWAPS : value.balancerSwaps;
|
||||
}
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
if (SwapInfoCache._isExpired(value)) {
|
||||
return undefined;
|
||||
}
|
||||
return value.balancerSwaps;
|
||||
}
|
||||
|
||||
public isFresh(takerToken: string, makerToken: string): boolean {
|
||||
const cached = this.getCachedSwapInfoForPair(takerToken, makerToken, false);
|
||||
return cached !== undefined;
|
||||
}
|
||||
|
||||
protected async _getAndSaveFreshSwapInfoForPairAsync(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
): Promise<BalancerSwaps> {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
const value = this._cache[key];
|
||||
if (value === undefined || value.expiresAt >= Date.now()) {
|
||||
const swapInfo = await this._fetchSwapInfoForPairAsync(takerToken, makerToken);
|
||||
const expiresAt = Date.now() + this._cacheTimeMs;
|
||||
this._cacheSwapInfoForPair(takerToken, makerToken, swapInfo, expiresAt);
|
||||
}
|
||||
return this._cache[key].balancerSwaps;
|
||||
}
|
||||
|
||||
protected _cacheSwapInfoForPair(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
swapInfo: BalancerSwaps,
|
||||
expiresAt: number,
|
||||
): void {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
this._cache[key] = {
|
||||
expiresAt,
|
||||
balancerSwaps: swapInfo,
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract _fetchSwapInfoForPairAsync(takerToken: string, makerToken: string): Promise<BalancerSwaps>;
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
import { Pool } from '@balancer-labs/sor/dist/types';
|
||||
import { Pool } from 'balancer-labs-sor-v1/dist/types';
|
||||
|
||||
import { ONE_HOUR_IN_SECONDS, ONE_SECOND_MS } from '../constants';
|
||||
export { Pool };
|
||||
|
@@ -0,0 +1,114 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { logUtils } from '@0x/utils';
|
||||
import { PoolDataService, SubgraphPoolBase } from '@balancer-labs/sdk';
|
||||
import { gql, request } from 'graphql-request';
|
||||
|
||||
const queryWithLinear = gql`
|
||||
query fetchTopPoolsWithLinear($maxPoolsFetched: Int!) {
|
||||
pools: pools(
|
||||
first: $maxPoolsFetched
|
||||
where: { swapEnabled: true }
|
||||
orderBy: totalLiquidity
|
||||
orderDirection: desc
|
||||
) {
|
||||
id
|
||||
address
|
||||
poolType
|
||||
swapFee
|
||||
totalShares
|
||||
tokens {
|
||||
address
|
||||
balance
|
||||
decimals
|
||||
weight
|
||||
priceRate
|
||||
}
|
||||
tokensList
|
||||
totalWeight
|
||||
amp
|
||||
expiryTime
|
||||
unitSeconds
|
||||
principalToken
|
||||
baseToken
|
||||
swapEnabled
|
||||
wrappedIndex
|
||||
mainIndex
|
||||
lowerTarget
|
||||
upperTarget
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const queryWithOutLinear = gql`
|
||||
query fetchTopPoolsWithoutLinear($maxPoolsFetched: Int!) {
|
||||
pools: pools(
|
||||
first: $maxPoolsFetched
|
||||
where: { swapEnabled: true }
|
||||
orderBy: totalLiquidity
|
||||
orderDirection: desc
|
||||
) {
|
||||
id
|
||||
address
|
||||
poolType
|
||||
swapFee
|
||||
totalShares
|
||||
tokens {
|
||||
address
|
||||
balance
|
||||
decimals
|
||||
weight
|
||||
priceRate
|
||||
}
|
||||
tokensList
|
||||
totalWeight
|
||||
amp
|
||||
expiryTime
|
||||
unitSeconds
|
||||
principalToken
|
||||
baseToken
|
||||
swapEnabled
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const QUERY_BY_CHAIN_ID: { [chainId: number]: string } = {
|
||||
[ChainId.Mainnet]: queryWithLinear,
|
||||
[ChainId.Polygon]: queryWithOutLinear,
|
||||
};
|
||||
|
||||
const DEFAULT_MAX_POOLS_FETCHED = 96;
|
||||
|
||||
/**
|
||||
* Simple service to query required info from Subgraph for Balancer Pools.
|
||||
* Because Balancer Subgraphs have slightly different schema depending on network the queries are adjusted as needed.
|
||||
*/
|
||||
export class SubgraphPoolDataService implements PoolDataService {
|
||||
private readonly _gqlQuery: string | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly _config: {
|
||||
chainId: number;
|
||||
subgraphUrl: string | null;
|
||||
maxPoolsFetched?: number;
|
||||
},
|
||||
) {
|
||||
this._config.maxPoolsFetched = this._config.maxPoolsFetched || DEFAULT_MAX_POOLS_FETCHED;
|
||||
this._gqlQuery = QUERY_BY_CHAIN_ID[this._config.chainId];
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: async-suffix
|
||||
public async getPools(): Promise<SubgraphPoolBase[]> {
|
||||
if (!this._gqlQuery || !this._config.subgraphUrl) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const { pools } = await request<{ pools: SubgraphPoolBase[] }>(this._config.subgraphUrl, this._gqlQuery, {
|
||||
maxPoolsFetched: this._config.maxPoolsFetched,
|
||||
});
|
||||
return pools;
|
||||
} catch (err) {
|
||||
logUtils.warn(`Failed to fetch BalancerV2 subgraph pools: ${err.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,9 +5,8 @@ import { SamplerOverrides } from '../../types';
|
||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
|
||||
import { BancorService } from './bancor_service';
|
||||
import { PoolsCache } from './pools_cache';
|
||||
import { SamplerOperations } from './sampler_operations';
|
||||
import { BatchedOperation, ERC20BridgeSource, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
|
||||
import { PoolsCacheMap, SamplerOperations } from './sampler_operations';
|
||||
import { BatchedOperation, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
|
||||
|
||||
/**
|
||||
* Generate sample amounts up to `maxFillAmount`.
|
||||
@@ -37,7 +36,7 @@ export class DexOrderSampler extends SamplerOperations {
|
||||
public readonly chainId: ChainId,
|
||||
_samplerContract: ERC20BridgeSamplerContract,
|
||||
private readonly _samplerOverrides?: SamplerOverrides,
|
||||
poolsCaches?: { [key in ERC20BridgeSource]: PoolsCache },
|
||||
poolsCaches?: PoolsCacheMap,
|
||||
tokenAdjacencyGraph?: TokenAdjacencyGraph,
|
||||
liquidityProviderRegistry?: LiquidityProviderRegistry,
|
||||
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
|
||||
|
@@ -13,9 +13,8 @@ import { BancorService } from './bancor_service';
|
||||
import {
|
||||
getCurveLikeInfosForPair,
|
||||
getDodoV2Offsets,
|
||||
getKyberOffsets,
|
||||
getPlatypusInfoForPair,
|
||||
getShellLikeInfosForPair,
|
||||
isAllowedKyberReserveId,
|
||||
isBadTokenForSource,
|
||||
isValidAddress,
|
||||
uniswapV2LikeRouterAddress,
|
||||
@@ -23,17 +22,21 @@ import {
|
||||
import { CompoundCTokenCache } from './compound_ctoken_cache';
|
||||
import {
|
||||
AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID,
|
||||
AVALANCHE_TOKENS,
|
||||
BALANCER_V2_VAULT_ADDRESS_BY_CHAIN,
|
||||
BANCOR_REGISTRY_BY_CHAIN_ID,
|
||||
BANCORV3_NETWORK_BY_CHAIN_ID,
|
||||
BANCORV3_NETWORK_INFO_BY_CHAIN_ID,
|
||||
BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN,
|
||||
BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN,
|
||||
COMPOUND_API_URL_BY_CHAIN_ID,
|
||||
DODOV1_CONFIG_BY_CHAIN_ID,
|
||||
DODOV2_FACTORIES_BY_CHAIN_ID,
|
||||
KYBER_CONFIG_BY_CHAIN_ID,
|
||||
GMX_READER_BY_CHAIN_ID,
|
||||
GMX_ROUTER_BY_CHAIN_ID,
|
||||
GMX_VAULT_BY_CHAIN_ID,
|
||||
KYBER_DMM_ROUTER_BY_CHAIN_ID,
|
||||
LIDO_INFO_BY_CHAIN,
|
||||
LINKSWAP_ROUTER_BY_CHAIN_ID,
|
||||
LIQUIDITY_PROVIDER_REGISTRY_BY_CHAIN_ID,
|
||||
MAINNET_TOKENS,
|
||||
MAKER_PSM_INFO_BY_CHAIN_ID,
|
||||
@@ -41,16 +44,18 @@ import {
|
||||
MOONISWAP_REGISTRIES_BY_CHAIN_ID,
|
||||
NATIVE_FEE_TOKEN_BY_CHAIN_ID,
|
||||
NULL_ADDRESS,
|
||||
NULL_BYTES,
|
||||
PLATYPUS_ROUTER_BY_CHAIN_ID,
|
||||
SELL_SOURCE_FILTER_BY_CHAIN_ID,
|
||||
UNISWAPV1_ROUTER_BY_CHAIN_ID,
|
||||
UNISWAPV3_CONFIG_BY_CHAIN_ID,
|
||||
VELODROME_ROUTER_BY_CHAIN_ID,
|
||||
ZERO_AMOUNT,
|
||||
} from './constants';
|
||||
import { getGeistInfoForPair } from './geist_utils';
|
||||
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
||||
import { getIntermediateTokens } from './multihop_utils';
|
||||
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache';
|
||||
import { BalancerV2SwapInfoCache } from './pools_cache/balancer_v2_utils_new';
|
||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||
import { SamplerNoOperation } from './sampler_no_operation';
|
||||
import { SourceFilters } from './source_filters';
|
||||
@@ -58,6 +63,8 @@ import {
|
||||
AaveV2FillData,
|
||||
AaveV2Info,
|
||||
BalancerFillData,
|
||||
BalancerSwapInfo,
|
||||
BalancerV2BatchSwapFillData,
|
||||
BalancerV2FillData,
|
||||
BalancerV2PoolInfo,
|
||||
BancorFillData,
|
||||
@@ -71,10 +78,9 @@ import {
|
||||
GeistFillData,
|
||||
GeistInfo,
|
||||
GenericRouterFillData,
|
||||
GMXFillData,
|
||||
HopInfo,
|
||||
KyberDmmFillData,
|
||||
KyberFillData,
|
||||
KyberSamplerOpts,
|
||||
LidoFillData,
|
||||
LidoInfo,
|
||||
LiquidityProviderFillData,
|
||||
@@ -82,6 +88,7 @@ import {
|
||||
MakerPsmFillData,
|
||||
MooniswapFillData,
|
||||
MultiHopFillData,
|
||||
PlatypusFillData,
|
||||
PsmInfo,
|
||||
ShellFillData,
|
||||
SourceQuoteOperation,
|
||||
@@ -89,6 +96,7 @@ import {
|
||||
TokenAdjacencyGraph,
|
||||
UniswapV2FillData,
|
||||
UniswapV3FillData,
|
||||
VelodromeFillData,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
@@ -103,6 +111,10 @@ export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
|
||||
*/
|
||||
export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]);
|
||||
|
||||
export type PoolsCacheMap = { [key in Exclude<SourcesWithPoolsCache, ERC20BridgeSource.BalancerV2>]: PoolsCache } & {
|
||||
[ERC20BridgeSource.BalancerV2]: BalancerV2SwapInfoCache | undefined;
|
||||
};
|
||||
|
||||
// tslint:disable:no-inferred-empty-object-type no-unbound-method
|
||||
|
||||
/**
|
||||
@@ -111,7 +123,7 @@ export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSour
|
||||
*/
|
||||
export class SamplerOperations {
|
||||
public readonly liquidityProviderRegistry: LiquidityProviderRegistry;
|
||||
public readonly poolsCaches: { [key in SourcesWithPoolsCache]: PoolsCache };
|
||||
public readonly poolsCaches: PoolsCacheMap;
|
||||
public readonly aaveReservesCache: AaveV2ReservesCache | undefined;
|
||||
public readonly compoundCTokenCache: CompoundCTokenCache | undefined;
|
||||
protected _bancorService?: BancorService;
|
||||
@@ -126,7 +138,7 @@ export class SamplerOperations {
|
||||
constructor(
|
||||
public readonly chainId: ChainId,
|
||||
protected readonly _samplerContract: ERC20BridgeSamplerContract,
|
||||
poolsCaches?: { [key in SourcesWithPoolsCache]: PoolsCache },
|
||||
poolsCaches?: PoolsCacheMap,
|
||||
protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [] },
|
||||
liquidityProviderRegistry: LiquidityProviderRegistry = {},
|
||||
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
|
||||
@@ -138,13 +150,16 @@ export class SamplerOperations {
|
||||
this.poolsCaches = poolsCaches
|
||||
? poolsCaches
|
||||
: {
|
||||
[ERC20BridgeSource.BalancerV2]: new BalancerV2PoolsCache(chainId),
|
||||
[ERC20BridgeSource.Beethovenx]: new BalancerV2PoolsCache(
|
||||
chainId,
|
||||
BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN[chainId],
|
||||
),
|
||||
[ERC20BridgeSource.Balancer]: new BalancerPoolsCache(),
|
||||
[ERC20BridgeSource.Cream]: new CreamPoolsCache(),
|
||||
[ERC20BridgeSource.BalancerV2]:
|
||||
BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[chainId] === NULL_ADDRESS
|
||||
? undefined
|
||||
: new BalancerV2SwapInfoCache(chainId),
|
||||
};
|
||||
|
||||
const aaveSubgraphUrl = AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID[chainId];
|
||||
@@ -250,54 +265,6 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getKyberSellQuotes(
|
||||
kyberOpts: KyberSamplerOpts,
|
||||
reserveOffset: BigNumber,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Kyber,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromKyberNetwork,
|
||||
params: [{ ...kyberOpts, reserveOffset, hint: NULL_BYTES }, takerToken, makerToken, takerFillAmounts],
|
||||
callback: (callResults: string, fillData: KyberFillData): BigNumber[] => {
|
||||
const [reserveId, hint, samples] = this._samplerContract.getABIDecodedReturnData<
|
||||
[string, string, BigNumber[]]
|
||||
>('sampleSellsFromKyberNetwork', callResults);
|
||||
fillData.hint = hint;
|
||||
fillData.reserveId = reserveId;
|
||||
fillData.networkProxy = kyberOpts.networkProxy;
|
||||
return isAllowedKyberReserveId(reserveId) ? samples : [];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getKyberBuyQuotes(
|
||||
kyberOpts: KyberSamplerOpts,
|
||||
reserveOffset: BigNumber,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Kyber,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromKyberNetwork,
|
||||
params: [{ ...kyberOpts, reserveOffset, hint: NULL_BYTES }, takerToken, makerToken, makerFillAmounts],
|
||||
callback: (callResults: string, fillData: KyberFillData): BigNumber[] => {
|
||||
const [reserveId, hint, samples] = this._samplerContract.getABIDecodedReturnData<
|
||||
[string, string, BigNumber[]]
|
||||
>('sampleBuysFromKyberNetwork', callResults);
|
||||
fillData.hint = hint;
|
||||
fillData.reserveId = reserveId;
|
||||
fillData.networkProxy = kyberOpts.networkProxy;
|
||||
return isAllowedKyberReserveId(reserveId) ? samples : [];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getKyberDmmSellQuotes(
|
||||
router: string,
|
||||
tokenAddressPath: string[],
|
||||
@@ -564,6 +531,49 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getBalancerV2MultihopSellQuotes(
|
||||
vault: string,
|
||||
quoteSwaps: BalancerSwapInfo, // Should always be sell swap steps.
|
||||
fillSwaps: BalancerSwapInfo, // Should always be sell swap steps.
|
||||
takerFillAmounts: BigNumber[],
|
||||
source: ERC20BridgeSource,
|
||||
): SourceQuoteOperation<BalancerV2BatchSwapFillData> {
|
||||
const quoteSwapSteps = quoteSwaps.swapSteps.map(s => ({
|
||||
...s,
|
||||
assetInIndex: new BigNumber(s.assetInIndex),
|
||||
assetOutIndex: new BigNumber(s.assetOutIndex),
|
||||
}));
|
||||
return new SamplerContractOperation({
|
||||
source,
|
||||
fillData: { vault, swapSteps: fillSwaps.swapSteps, assets: fillSwaps.assets },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleMultihopSellsFromBalancerV2,
|
||||
params: [vault, quoteSwapSteps, quoteSwaps.assets, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getBalancerV2MultihopBuyQuotes(
|
||||
vault: string,
|
||||
quoteSwaps: BalancerSwapInfo, // Should always be buy swap steps.
|
||||
fillSwaps: BalancerSwapInfo, // Should always be a sell quote.
|
||||
makerFillAmounts: BigNumber[],
|
||||
source: ERC20BridgeSource,
|
||||
): SourceQuoteOperation<BalancerV2BatchSwapFillData> {
|
||||
const quoteSwapSteps = quoteSwaps.swapSteps.map(s => ({
|
||||
...s,
|
||||
assetInIndex: new BigNumber(s.assetInIndex),
|
||||
assetOutIndex: new BigNumber(s.assetOutIndex),
|
||||
}));
|
||||
return new SamplerContractOperation({
|
||||
source,
|
||||
// NOTE: fillData is set up for sells but quote function is set up for buys.
|
||||
fillData: { vault, swapSteps: fillSwaps.swapSteps, assets: fillSwaps.assets },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleMultihopBuysFromBalancerV2,
|
||||
params: [vault, quoteSwapSteps, quoteSwaps.assets, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getBalancerV2SellQuotes(
|
||||
poolInfo: BalancerV2PoolInfo,
|
||||
makerToken: string,
|
||||
@@ -704,6 +714,36 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getBancorV3SellQuotes(
|
||||
networkAddress: string,
|
||||
networkInfoAddress: string,
|
||||
path: string[],
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<BancorFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.BancorV3,
|
||||
fillData: { networkAddress, path },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromBancorV3,
|
||||
params: [MAINNET_TOKENS.WETH, networkInfoAddress, path, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getBancorV3BuyQuotes(
|
||||
networkAddress: string,
|
||||
networkInfoAddress: string,
|
||||
path: string[],
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<BancorFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.BancorV3,
|
||||
fillData: { networkAddress, path },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromBancorV3,
|
||||
params: [MAINNET_TOKENS.WETH, networkInfoAddress, path, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getMooniswapSellQuotes(
|
||||
registry: string,
|
||||
makerToken: string,
|
||||
@@ -1101,8 +1141,10 @@ export class SamplerOperations {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Lido,
|
||||
fillData: {
|
||||
makerToken,
|
||||
takerToken,
|
||||
stEthTokenAddress: lidoInfo.stEthToken,
|
||||
wstEthTokenAddress: lidoInfo.wstEthToken,
|
||||
},
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromLido,
|
||||
@@ -1119,8 +1161,10 @@ export class SamplerOperations {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Lido,
|
||||
fillData: {
|
||||
makerToken,
|
||||
takerToken,
|
||||
stEthTokenAddress: lidoInfo.stEthToken,
|
||||
wstEthTokenAddress: lidoInfo.wstEthToken,
|
||||
},
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromLido,
|
||||
@@ -1214,6 +1258,113 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getGMXSellQuotes(
|
||||
router: string,
|
||||
reader: string,
|
||||
vault: string,
|
||||
tokenAddressPath: string[],
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<GMXFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.GMX,
|
||||
fillData: { router, reader, vault, tokenAddressPath },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromGMX,
|
||||
params: [reader, vault, tokenAddressPath, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
public getGMXBuyQuotes(
|
||||
router: string,
|
||||
reader: string,
|
||||
vault: string,
|
||||
tokenAddressPath: string[],
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<GMXFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.GMX,
|
||||
fillData: { router, reader, vault, tokenAddressPath },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromGMX,
|
||||
params: [reader, vault, tokenAddressPath, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getPlatypusSellQuotes(
|
||||
router: string,
|
||||
pool: string[],
|
||||
tokenAddressPath: string[],
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<PlatypusFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Platypus,
|
||||
fillData: { router, pool, tokenAddressPath },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromPlatypus,
|
||||
params: [pool[0], tokenAddressPath, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getPlatypusBuyQuotes(
|
||||
router: string,
|
||||
pool: string[],
|
||||
tokenAddressPath: string[],
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<PlatypusFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Platypus,
|
||||
fillData: { router, pool, tokenAddressPath },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromPlatypus,
|
||||
params: [pool[0], tokenAddressPath, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getVelodromeSellQuotes(
|
||||
router: string,
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<VelodromeFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Velodrome,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromVelodrome,
|
||||
params: [router, takerToken, makerToken, takerFillAmounts],
|
||||
callback: (callResults: string, fillData: VelodromeFillData): BigNumber[] => {
|
||||
const [isStable, samples] = this._samplerContract.getABIDecodedReturnData<[boolean, BigNumber[]]>(
|
||||
'sampleSellsFromVelodrome',
|
||||
callResults,
|
||||
);
|
||||
fillData.router = router;
|
||||
fillData.stable = isStable;
|
||||
return samples;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getVelodromeBuyQuotes(
|
||||
router: string,
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<VelodromeFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Velodrome,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromVelodrome,
|
||||
params: [router, takerToken, makerToken, makerFillAmounts],
|
||||
callback: (callResults: string, fillData: VelodromeFillData): BigNumber[] => {
|
||||
const [isStable, samples] = this._samplerContract.getABIDecodedReturnData<[boolean, BigNumber[]]>(
|
||||
'sampleBuysFromVelodrome',
|
||||
callResults,
|
||||
);
|
||||
fillData.router = router;
|
||||
fillData.stable = isStable;
|
||||
return samples;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getMedianSellRate(
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
@@ -1299,7 +1450,7 @@ export class SamplerOperations {
|
||||
takerFillAmounts: BigNumber[],
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph = this.tokenAdjacencyGraph,
|
||||
): SourceQuoteOperation[] {
|
||||
// Find the adjacent tokens in the provided tooken adjacency graph,
|
||||
// Find the adjacent tokens in the provided token adjacency graph,
|
||||
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
|
||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph);
|
||||
// Drop out MultiHop and Native as we do not query those here.
|
||||
@@ -1312,8 +1463,6 @@ export class SamplerOperations {
|
||||
return [];
|
||||
}
|
||||
switch (source) {
|
||||
case ERC20BridgeSource.Eth2Dai:
|
||||
return [];
|
||||
case ERC20BridgeSource.Uniswap:
|
||||
return isValidAddress(UNISWAPV1_ROUTER_BY_CHAIN_ID[this.chainId])
|
||||
? this.getUniswapSellQuotes(
|
||||
@@ -1330,22 +1479,23 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.PancakeSwapV2:
|
||||
case ERC20BridgeSource.BakerySwap:
|
||||
case ERC20BridgeSource.ApeSwap:
|
||||
case ERC20BridgeSource.CafeSwap:
|
||||
case ERC20BridgeSource.CheeseSwap:
|
||||
case ERC20BridgeSource.JulSwap:
|
||||
case ERC20BridgeSource.QuickSwap:
|
||||
case ERC20BridgeSource.ComethSwap:
|
||||
case ERC20BridgeSource.Dfyn:
|
||||
case ERC20BridgeSource.WaultSwap:
|
||||
case ERC20BridgeSource.Polydex:
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
case ERC20BridgeSource.UbeSwap:
|
||||
case ERC20BridgeSource.SpiritSwap:
|
||||
case ERC20BridgeSource.SpookySwap:
|
||||
case ERC20BridgeSource.Yoshi:
|
||||
case ERC20BridgeSource.MorpheusSwap:
|
||||
case ERC20BridgeSource.BiSwap:
|
||||
case ERC20BridgeSource.MDex:
|
||||
case ERC20BridgeSource.KnightSwap:
|
||||
case ERC20BridgeSource.MeshSwap:
|
||||
const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source);
|
||||
if (!isValidAddress(uniLikeRouter)) {
|
||||
return [];
|
||||
@@ -1360,20 +1510,8 @@ export class SamplerOperations {
|
||||
return [];
|
||||
}
|
||||
return this.getKyberDmmSellQuotes(kyberDmmRouter, [takerToken, makerToken], takerFillAmounts);
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return getKyberOffsets().map(offset =>
|
||||
this.getKyberSellQuotes(
|
||||
KYBER_CONFIG_BY_CHAIN_ID[this.chainId],
|
||||
offset,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.Curve:
|
||||
case ERC20BridgeSource.CurveV2:
|
||||
case ERC20BridgeSource.Swerve:
|
||||
case ERC20BridgeSource.SnowSwap:
|
||||
case ERC20BridgeSource.Nerve:
|
||||
case ERC20BridgeSource.Synapse:
|
||||
case ERC20BridgeSource.Belt:
|
||||
@@ -1383,6 +1521,7 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.FirebirdOneSwap:
|
||||
case ERC20BridgeSource.IronSwap:
|
||||
case ERC20BridgeSource.ACryptos:
|
||||
case ERC20BridgeSource.MobiusMoney:
|
||||
return getCurveLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool =>
|
||||
this.getCurveSellQuotes(
|
||||
pool,
|
||||
@@ -1447,15 +1586,27 @@ export class SamplerOperations {
|
||||
ERC20BridgeSource.Balancer,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.BalancerV2:
|
||||
case ERC20BridgeSource.Beethovenx:
|
||||
case ERC20BridgeSource.BalancerV2: {
|
||||
const cache = this.poolsCaches[source];
|
||||
if (!cache) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const swaps = cache.getCachedSwapInfoForPair(takerToken, makerToken);
|
||||
const vault = BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
if (!swaps || vault === NULL_ADDRESS) {
|
||||
return [];
|
||||
}
|
||||
// Changed to retrieve queryBatchSwap for swap steps > 1 of length
|
||||
return swaps.swapInfoExactIn.map(swapInfo =>
|
||||
this.getBalancerV2MultihopSellQuotes(vault, swapInfo, swapInfo, takerFillAmounts, source),
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Beethovenx: {
|
||||
const poolIds =
|
||||
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
||||
|
||||
const vault =
|
||||
source === ERC20BridgeSource.BalancerV2
|
||||
? BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId]
|
||||
: BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
if (vault === NULL_ADDRESS) {
|
||||
return [];
|
||||
}
|
||||
@@ -1468,6 +1619,7 @@ export class SamplerOperations {
|
||||
source,
|
||||
),
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Cream:
|
||||
return (
|
||||
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
||||
@@ -1519,23 +1671,6 @@ export class SamplerOperations {
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
);
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
if (!isValidAddress(LINKSWAP_ROUTER_BY_CHAIN_ID[this.chainId])) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
[takerToken, makerToken],
|
||||
...getIntermediateTokens(makerToken, takerToken, {
|
||||
default: [MAINNET_TOKENS.LINK, MAINNET_TOKENS.WETH],
|
||||
}).map(t => [takerToken, t, makerToken]),
|
||||
].map(path =>
|
||||
this.getUniswapV2SellQuotes(
|
||||
LINKSWAP_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
path,
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.MakerPsm:
|
||||
const psmInfo = MAKER_PSM_INFO_BY_CHAIN_ID[this.chainId];
|
||||
if (!isValidAddress(psmInfo.psmAddress)) {
|
||||
@@ -1553,16 +1688,10 @@ export class SamplerOperations {
|
||||
].map(path => this.getUniswapV3SellQuotes(router, quoter, path, takerFillAmounts));
|
||||
}
|
||||
case ERC20BridgeSource.Lido: {
|
||||
const lidoInfo = LIDO_INFO_BY_CHAIN[this.chainId];
|
||||
if (
|
||||
lidoInfo.stEthToken === NULL_ADDRESS ||
|
||||
lidoInfo.wethToken === NULL_ADDRESS ||
|
||||
takerToken.toLowerCase() !== lidoInfo.wethToken.toLowerCase() ||
|
||||
makerToken.toLowerCase() !== lidoInfo.stEthToken.toLowerCase()
|
||||
) {
|
||||
if (!this._isLidoSupported(takerToken, makerToken)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const lidoInfo = LIDO_INFO_BY_CHAIN[this.chainId];
|
||||
return this.getLidoSellQuotes(lidoInfo, makerToken, takerToken, takerFillAmounts);
|
||||
}
|
||||
case ERC20BridgeSource.AaveV2: {
|
||||
@@ -1604,6 +1733,45 @@ export class SamplerOperations {
|
||||
takerFillAmounts,
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.GMX: {
|
||||
// low liquidity mim pool dont quote
|
||||
if (takerToken === AVALANCHE_TOKENS.MIM || makerToken === 'AVALANCHE_TOKENS.MIM') {
|
||||
return [];
|
||||
}
|
||||
return this.getGMXSellQuotes(
|
||||
GMX_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
GMX_READER_BY_CHAIN_ID[this.chainId],
|
||||
GMX_VAULT_BY_CHAIN_ID[this.chainId],
|
||||
[takerToken, makerToken],
|
||||
takerFillAmounts,
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Platypus: {
|
||||
return getPlatypusInfoForPair(this.chainId, takerToken, makerToken).map(pool =>
|
||||
this.getPlatypusSellQuotes(
|
||||
PLATYPUS_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
[pool.poolAddress],
|
||||
[takerToken, makerToken],
|
||||
takerFillAmounts,
|
||||
),
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.BancorV3: {
|
||||
return this.getBancorV3SellQuotes(
|
||||
BANCORV3_NETWORK_BY_CHAIN_ID[this.chainId],
|
||||
BANCORV3_NETWORK_INFO_BY_CHAIN_ID[this.chainId],
|
||||
[takerToken, makerToken],
|
||||
takerFillAmounts,
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Velodrome: {
|
||||
return this.getVelodromeSellQuotes(
|
||||
VELODROME_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerFillAmounts,
|
||||
);
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||
}
|
||||
@@ -1612,6 +1780,24 @@ export class SamplerOperations {
|
||||
return allOps;
|
||||
}
|
||||
|
||||
private _isLidoSupported(takerTokenAddress: string, makerTokenAddress: string): boolean {
|
||||
const lidoInfo = LIDO_INFO_BY_CHAIN[this.chainId];
|
||||
if (lidoInfo.wethToken === NULL_ADDRESS) {
|
||||
return false;
|
||||
}
|
||||
const takerToken = takerTokenAddress.toLowerCase();
|
||||
const makerToken = makerTokenAddress.toLowerCase();
|
||||
const wethToken = lidoInfo.wethToken.toLowerCase();
|
||||
const stEthToken = lidoInfo.stEthToken.toLowerCase();
|
||||
const wstEthToken = lidoInfo.wstEthToken.toLowerCase();
|
||||
|
||||
if (takerToken === wethToken && makerToken === stEthToken) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return _.difference([stEthToken, wstEthToken], [takerToken, makerToken]).length === 0;
|
||||
}
|
||||
|
||||
private _getBuyQuoteOperations(
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
@@ -1625,8 +1811,6 @@ export class SamplerOperations {
|
||||
return _.flatten(
|
||||
_sources.map((source): SourceQuoteOperation | SourceQuoteOperation[] => {
|
||||
switch (source) {
|
||||
case ERC20BridgeSource.Eth2Dai:
|
||||
return [];
|
||||
case ERC20BridgeSource.Uniswap:
|
||||
return isValidAddress(UNISWAPV1_ROUTER_BY_CHAIN_ID[this.chainId])
|
||||
? this.getUniswapBuyQuotes(
|
||||
@@ -1643,22 +1827,23 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.PancakeSwapV2:
|
||||
case ERC20BridgeSource.BakerySwap:
|
||||
case ERC20BridgeSource.ApeSwap:
|
||||
case ERC20BridgeSource.CafeSwap:
|
||||
case ERC20BridgeSource.CheeseSwap:
|
||||
case ERC20BridgeSource.JulSwap:
|
||||
case ERC20BridgeSource.QuickSwap:
|
||||
case ERC20BridgeSource.ComethSwap:
|
||||
case ERC20BridgeSource.Dfyn:
|
||||
case ERC20BridgeSource.WaultSwap:
|
||||
case ERC20BridgeSource.Polydex:
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
case ERC20BridgeSource.UbeSwap:
|
||||
case ERC20BridgeSource.SpiritSwap:
|
||||
case ERC20BridgeSource.SpookySwap:
|
||||
case ERC20BridgeSource.Yoshi:
|
||||
case ERC20BridgeSource.MorpheusSwap:
|
||||
case ERC20BridgeSource.BiSwap:
|
||||
case ERC20BridgeSource.MDex:
|
||||
case ERC20BridgeSource.KnightSwap:
|
||||
case ERC20BridgeSource.MeshSwap:
|
||||
const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source);
|
||||
if (!isValidAddress(uniLikeRouter)) {
|
||||
return [];
|
||||
@@ -1673,20 +1858,8 @@ export class SamplerOperations {
|
||||
return [];
|
||||
}
|
||||
return this.getKyberDmmBuyQuotes(kyberDmmRouter, [takerToken, makerToken], makerFillAmounts);
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return getKyberOffsets().map(offset =>
|
||||
this.getKyberBuyQuotes(
|
||||
KYBER_CONFIG_BY_CHAIN_ID[this.chainId],
|
||||
offset,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.Curve:
|
||||
case ERC20BridgeSource.CurveV2:
|
||||
case ERC20BridgeSource.Swerve:
|
||||
case ERC20BridgeSource.SnowSwap:
|
||||
case ERC20BridgeSource.Nerve:
|
||||
case ERC20BridgeSource.Synapse:
|
||||
case ERC20BridgeSource.Belt:
|
||||
@@ -1696,6 +1869,7 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.FirebirdOneSwap:
|
||||
case ERC20BridgeSource.IronSwap:
|
||||
case ERC20BridgeSource.ACryptos:
|
||||
case ERC20BridgeSource.MobiusMoney:
|
||||
return getCurveLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool =>
|
||||
this.getCurveBuyQuotes(
|
||||
pool,
|
||||
@@ -1760,15 +1934,33 @@ export class SamplerOperations {
|
||||
ERC20BridgeSource.Balancer,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.BalancerV2:
|
||||
case ERC20BridgeSource.Beethovenx:
|
||||
case ERC20BridgeSource.BalancerV2: {
|
||||
const cache = this.poolsCaches[source];
|
||||
if (!cache) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const swaps = cache.getCachedSwapInfoForPair(takerToken, makerToken);
|
||||
const vault = BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
if (!swaps || vault === NULL_ADDRESS) {
|
||||
return [];
|
||||
}
|
||||
// Changed to retrieve queryBatchSwap for swap steps > 1 of length
|
||||
return swaps.swapInfoExactOut.map((quoteSwapInfo, i) =>
|
||||
this.getBalancerV2MultihopBuyQuotes(
|
||||
vault,
|
||||
quoteSwapInfo,
|
||||
swaps.swapInfoExactIn[i],
|
||||
makerFillAmounts,
|
||||
source,
|
||||
),
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Beethovenx: {
|
||||
const poolIds =
|
||||
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
||||
|
||||
const vault =
|
||||
source === ERC20BridgeSource.BalancerV2
|
||||
? BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId]
|
||||
: BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
if (vault === NULL_ADDRESS) {
|
||||
return [];
|
||||
}
|
||||
@@ -1781,6 +1973,7 @@ export class SamplerOperations {
|
||||
source,
|
||||
),
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Cream:
|
||||
return (
|
||||
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
||||
@@ -1826,24 +2019,6 @@ export class SamplerOperations {
|
||||
// Unimplemented
|
||||
// return this.getBancorBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
return [];
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
if (!isValidAddress(LINKSWAP_ROUTER_BY_CHAIN_ID[this.chainId])) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
[takerToken, makerToken],
|
||||
// LINK is the base asset in many of the pools on Linkswap
|
||||
...getIntermediateTokens(makerToken, takerToken, {
|
||||
default: [MAINNET_TOKENS.LINK, MAINNET_TOKENS.WETH],
|
||||
}).map(t => [takerToken, t, makerToken]),
|
||||
].map(path =>
|
||||
this.getUniswapV2BuyQuotes(
|
||||
LINKSWAP_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
path,
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.MakerPsm:
|
||||
const psmInfo = MAKER_PSM_INFO_BY_CHAIN_ID[this.chainId];
|
||||
if (!isValidAddress(psmInfo.psmAddress)) {
|
||||
@@ -1861,17 +2036,10 @@ export class SamplerOperations {
|
||||
].map(path => this.getUniswapV3BuyQuotes(router, quoter, path, makerFillAmounts));
|
||||
}
|
||||
case ERC20BridgeSource.Lido: {
|
||||
const lidoInfo = LIDO_INFO_BY_CHAIN[this.chainId];
|
||||
|
||||
if (
|
||||
lidoInfo.stEthToken === NULL_ADDRESS ||
|
||||
lidoInfo.wethToken === NULL_ADDRESS ||
|
||||
takerToken.toLowerCase() !== lidoInfo.wethToken.toLowerCase() ||
|
||||
makerToken.toLowerCase() !== lidoInfo.stEthToken.toLowerCase()
|
||||
) {
|
||||
if (!this._isLidoSupported(takerToken, makerToken)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const lidoInfo = LIDO_INFO_BY_CHAIN[this.chainId];
|
||||
return this.getLidoBuyQuotes(lidoInfo, makerToken, takerToken, makerFillAmounts);
|
||||
}
|
||||
case ERC20BridgeSource.AaveV2: {
|
||||
@@ -1907,6 +2075,45 @@ export class SamplerOperations {
|
||||
}
|
||||
return this.getCompoundBuyQuotes(cToken.tokenAddress, makerToken, takerToken, makerFillAmounts);
|
||||
}
|
||||
case ERC20BridgeSource.GMX: {
|
||||
// bad mim pool dont quote
|
||||
if (takerToken === 'AVALANCHE_TOKENS.MIM' || makerToken === 'AVALANCHE_TOKENS.MIM') {
|
||||
return [];
|
||||
}
|
||||
return this.getGMXBuyQuotes(
|
||||
GMX_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
GMX_READER_BY_CHAIN_ID[this.chainId],
|
||||
GMX_VAULT_BY_CHAIN_ID[this.chainId],
|
||||
[takerToken, makerToken],
|
||||
makerFillAmounts,
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Platypus: {
|
||||
return getPlatypusInfoForPair(this.chainId, takerToken, makerToken).map(pool =>
|
||||
this.getPlatypusBuyQuotes(
|
||||
PLATYPUS_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
[pool.poolAddress],
|
||||
[takerToken, makerToken],
|
||||
makerFillAmounts,
|
||||
),
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.BancorV3: {
|
||||
return this.getBancorV3BuyQuotes(
|
||||
BANCORV3_NETWORK_BY_CHAIN_ID[this.chainId],
|
||||
BANCORV3_NETWORK_INFO_BY_CHAIN_ID[this.chainId],
|
||||
[takerToken, makerToken],
|
||||
makerFillAmounts,
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Velodrome: {
|
||||
return this.getVelodromeBuyQuotes(
|
||||
VELODROME_ROUTER_BY_CHAIN_ID[this.chainId],
|
||||
takerToken,
|
||||
makerToken,
|
||||
makerFillAmounts,
|
||||
);
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||
}
|
||||
|
@@ -8,9 +8,9 @@ import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
|
||||
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../../utils/quote_requestor';
|
||||
import { IRfqClient } from '../irfq_client';
|
||||
import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from '../quote_report_generator';
|
||||
|
||||
import { CollapsedPath } from './path';
|
||||
import { SourceFilters } from './source_filters';
|
||||
|
||||
/**
|
||||
@@ -38,8 +38,6 @@ export enum ERC20BridgeSource {
|
||||
Native = 'Native',
|
||||
Uniswap = 'Uniswap',
|
||||
UniswapV2 = 'Uniswap_V2',
|
||||
Eth2Dai = 'Eth2Dai',
|
||||
Kyber = 'Kyber',
|
||||
Curve = 'Curve',
|
||||
LiquidityProvider = 'LiquidityProvider',
|
||||
MultiBridge = 'MultiBridge',
|
||||
@@ -52,13 +50,10 @@ export enum ERC20BridgeSource {
|
||||
Mooniswap = 'Mooniswap',
|
||||
MultiHop = 'MultiHop',
|
||||
Shell = 'Shell',
|
||||
Swerve = 'Swerve',
|
||||
SnowSwap = 'SnowSwap',
|
||||
SushiSwap = 'SushiSwap',
|
||||
Dodo = 'DODO',
|
||||
DodoV2 = 'DODO_V2',
|
||||
CryptoCom = 'CryptoCom',
|
||||
Linkswap = 'Linkswap',
|
||||
KyberDmm = 'KyberDMM',
|
||||
Smoothy = 'Smoothy',
|
||||
Component = 'Component',
|
||||
@@ -71,38 +66,46 @@ export enum ERC20BridgeSource {
|
||||
AaveV2 = 'Aave_V2',
|
||||
Compound = 'Compound',
|
||||
Synapse = 'Synapse',
|
||||
BancorV3 = 'BancorV3',
|
||||
// BSC only
|
||||
PancakeSwap = 'PancakeSwap',
|
||||
PancakeSwapV2 = 'PancakeSwap_V2',
|
||||
BiSwap = 'BiSwap',
|
||||
MDex = 'MDex',
|
||||
KnightSwap = 'KnightSwap',
|
||||
BakerySwap = 'BakerySwap',
|
||||
Nerve = 'Nerve',
|
||||
Belt = 'Belt',
|
||||
Ellipsis = 'Ellipsis',
|
||||
ApeSwap = 'ApeSwap',
|
||||
CafeSwap = 'CafeSwap',
|
||||
CheeseSwap = 'CheeseSwap',
|
||||
JulSwap = 'JulSwap',
|
||||
ACryptos = 'ACryptoS',
|
||||
// Polygon only
|
||||
QuickSwap = 'QuickSwap',
|
||||
ComethSwap = 'ComethSwap',
|
||||
Dfyn = 'Dfyn',
|
||||
WaultSwap = 'WaultSwap',
|
||||
Polydex = 'Polydex',
|
||||
FirebirdOneSwap = 'FirebirdOneSwap',
|
||||
JetSwap = 'JetSwap',
|
||||
IronSwap = 'IronSwap',
|
||||
MeshSwap = 'MeshSwap',
|
||||
// Avalanche
|
||||
Pangolin = 'Pangolin',
|
||||
TraderJoe = 'TraderJoe',
|
||||
Platypus = 'Platypus',
|
||||
// tslint:disable: enum-naming
|
||||
GMX = 'GMX',
|
||||
// Celo only
|
||||
UbeSwap = 'UbeSwap',
|
||||
MobiusMoney = 'MobiusMoney',
|
||||
// Fantom
|
||||
SpiritSwap = 'SpiritSwap',
|
||||
SpookySwap = 'SpookySwap',
|
||||
Beethovenx = 'Beethovenx',
|
||||
MorpheusSwap = 'MorpheusSwap',
|
||||
Yoshi = 'Yoshi',
|
||||
Geist = 'Geist',
|
||||
// Optimism
|
||||
Velodrome = 'Velodrome',
|
||||
}
|
||||
export type SourcesWithPoolsCache =
|
||||
| ERC20BridgeSource.Balancer
|
||||
@@ -166,6 +169,7 @@ export interface PsmInfo {
|
||||
export interface LidoInfo {
|
||||
stEthToken: string;
|
||||
wethToken: string;
|
||||
wstEthToken: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,6 +213,23 @@ export interface CurveFillData extends FillData {
|
||||
pool: CurveInfo;
|
||||
}
|
||||
|
||||
export interface BalancerBatchSwapStep {
|
||||
poolId: string;
|
||||
assetInIndex: number;
|
||||
assetOutIndex: number;
|
||||
amount: BigNumber;
|
||||
userData: string;
|
||||
}
|
||||
|
||||
export interface BalancerSwaps {
|
||||
swapInfoExactIn: BalancerSwapInfo[];
|
||||
swapInfoExactOut: BalancerSwapInfo[];
|
||||
}
|
||||
export interface BalancerSwapInfo {
|
||||
assets: string[];
|
||||
swapSteps: BalancerBatchSwapStep[];
|
||||
}
|
||||
|
||||
export interface BalancerFillData extends FillData {
|
||||
poolAddress: string;
|
||||
}
|
||||
@@ -218,6 +239,12 @@ export interface BalancerV2FillData extends FillData {
|
||||
poolId: string;
|
||||
}
|
||||
|
||||
export interface BalancerV2BatchSwapFillData extends FillData {
|
||||
vault: string;
|
||||
swapSteps: BalancerBatchSwapStep[];
|
||||
assets: string[];
|
||||
}
|
||||
|
||||
export interface UniswapV2FillData extends FillData {
|
||||
tokenAddressPath: string[];
|
||||
router: string;
|
||||
@@ -237,10 +264,9 @@ export interface BancorFillData extends FillData {
|
||||
networkAddress: string;
|
||||
}
|
||||
|
||||
export interface KyberFillData extends FillData {
|
||||
hint: string;
|
||||
reserveId: string;
|
||||
networkProxy: string;
|
||||
export interface BancorV3FillData extends FillData {
|
||||
path: string[];
|
||||
networkAddress: string;
|
||||
}
|
||||
|
||||
export interface MooniswapFillData extends FillData {
|
||||
@@ -307,7 +333,9 @@ export interface FinalUniswapV3FillData extends Omit<UniswapV3FillData, 'pathAmo
|
||||
|
||||
export interface LidoFillData extends FillData {
|
||||
stEthTokenAddress: string;
|
||||
wstEthTokenAddress: string;
|
||||
takerToken: string;
|
||||
makerToken: string;
|
||||
}
|
||||
|
||||
export interface AaveV2FillData extends FillData {
|
||||
@@ -330,6 +358,30 @@ export interface GeistFillData extends FillData {
|
||||
takerToken: string;
|
||||
}
|
||||
|
||||
export interface PlatypusInfo {
|
||||
poolAddress: string;
|
||||
tokens: string[];
|
||||
gasSchedule: number;
|
||||
}
|
||||
|
||||
export interface GMXFillData extends FillData {
|
||||
router: string;
|
||||
reader: string;
|
||||
vault: string;
|
||||
tokenAddressPath: string[];
|
||||
}
|
||||
|
||||
export interface PlatypusFillData extends FillData {
|
||||
router: string;
|
||||
pool: string[];
|
||||
tokenAddressPath: string[];
|
||||
}
|
||||
|
||||
export interface VelodromeFillData extends FillData {
|
||||
router: string;
|
||||
stable: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a node on a fill path.
|
||||
*/
|
||||
@@ -349,7 +401,7 @@ export interface Fill<TFillData extends FillData = FillData> {
|
||||
input: BigNumber;
|
||||
// Output fill amount (maker asset amount in a sell, taker asset amount in a buy).
|
||||
output: BigNumber;
|
||||
// The output fill amount, ajdusted by fees.
|
||||
// The output fill amount, adjusted by fees.
|
||||
adjustedOutput: BigNumber;
|
||||
// Fill that must precede this one. This enforces certain fills to be contiguous.
|
||||
parent?: Fill;
|
||||
@@ -427,6 +479,7 @@ export type OptimizedMarketOrder =
|
||||
| OptimizedMarketOrderBase<NativeRfqOrderFillData>;
|
||||
|
||||
export interface GetMarketOrdersRfqOpts extends RfqRequestOpts {
|
||||
rfqClient?: IRfqClient;
|
||||
quoteRequestor?: QuoteRequestor;
|
||||
firmQuoteValidator?: RfqFirmQuoteValidator;
|
||||
}
|
||||
@@ -579,7 +632,6 @@ export interface OptimizerResult {
|
||||
liquidityDelivered: CollapsedFill[] | DexSample<MultiHopFillData>;
|
||||
marketSideLiquidity: MarketSideLiquidity;
|
||||
adjustedRate: BigNumber;
|
||||
unoptimizedPath?: CollapsedPath;
|
||||
takerAmountPerEth: BigNumber;
|
||||
makerAmountPerEth: BigNumber;
|
||||
}
|
||||
@@ -611,6 +663,7 @@ export interface MarketSideLiquidity {
|
||||
takerTokenDecimals: number;
|
||||
quotes: RawQuotes;
|
||||
isRfqSupported: boolean;
|
||||
blockNumber: number;
|
||||
}
|
||||
|
||||
export interface RawQuotes {
|
||||
@@ -649,9 +702,3 @@ export interface GenerateOptimizedOrdersOpts {
|
||||
export interface ComparisonPrice {
|
||||
wholeOrder: BigNumber | undefined;
|
||||
}
|
||||
|
||||
export interface KyberSamplerOpts {
|
||||
networkProxy: string;
|
||||
hintHandler: string;
|
||||
weth: string;
|
||||
}
|
||||
|
@@ -106,6 +106,8 @@ export interface ExtendedQuoteReport {
|
||||
decodedUniqueId?: string;
|
||||
sourcesConsidered: ExtendedQuoteReportIndexedEntryOutbound[];
|
||||
sourcesDelivered: ExtendedQuoteReportIndexedEntryOutbound[] | undefined;
|
||||
blockNumber: number | undefined;
|
||||
estimatedGas: string;
|
||||
}
|
||||
|
||||
export interface PriceComparisonsReport {
|
||||
@@ -205,7 +207,7 @@ export function generateExtendedQuoteReportSources(
|
||||
..._.flatten(
|
||||
quotes.dexQuotes.map(dex =>
|
||||
dex
|
||||
.filter(quote => isDexSampleForTotalAmount(quote, marketOperation, amount))
|
||||
.filter(quote => isDexSampleFilter(quote, amount))
|
||||
.map(quote => dexSampleToReportSource(quote, marketOperation)),
|
||||
),
|
||||
),
|
||||
@@ -304,16 +306,9 @@ export function dexSampleToReportSource(ds: DexSample, marketOperation: MarketOp
|
||||
* Checks if a DEX sample is the one that represents the whole amount requested by taker
|
||||
* NOTE: this is used for the QuoteReport to filter samples
|
||||
*/
|
||||
function isDexSampleForTotalAmount(ds: DexSample, marketOperation: MarketOperation, amount: BigNumber): boolean {
|
||||
// input and output map to different values
|
||||
// based on the market operation
|
||||
if (marketOperation === MarketOperation.Buy) {
|
||||
return ds.input === amount;
|
||||
} else if (marketOperation === MarketOperation.Sell) {
|
||||
return ds.output === amount;
|
||||
} else {
|
||||
throw new Error(`Unexpected marketOperation ${marketOperation}`);
|
||||
}
|
||||
function isDexSampleFilter(ds: DexSample, amount: BigNumber): boolean {
|
||||
// The entry is for the total amont, not a sampler entry && there was liquidity in the source
|
||||
return ds.input.eq(amount) && ds.output.isGreaterThan(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
16
packages/asset-swapper/src/utils/rfq_client_mappers.ts
Normal file
16
packages/asset-swapper/src/utils/rfq_client_mappers.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
|
||||
|
||||
import { SignedNativeOrder } from '../types';
|
||||
|
||||
import { RfqClientV1Quote } from './irfq_client';
|
||||
|
||||
/**
|
||||
* Converts a RfqClientRfqOrderFirmQuote to a SignedNativeOrder
|
||||
*/
|
||||
export const toSignedNativeOrder = (quote: RfqClientV1Quote): SignedNativeOrder => {
|
||||
return {
|
||||
type: FillQuoteTransformerOrderType.Rfq,
|
||||
order: quote.order,
|
||||
signature: quote.signature,
|
||||
};
|
||||
};
|
@@ -8,66 +8,74 @@ import { ContractArtifact } from 'ethereum-types';
|
||||
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
|
||||
import * as BalanceChecker from '../test/generated-artifacts/BalanceChecker.json';
|
||||
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
|
||||
import * as BalancerV2BatchSampler from '../test/generated-artifacts/BalancerV2BatchSampler.json';
|
||||
import * as BalancerV2Common from '../test/generated-artifacts/BalancerV2Common.json';
|
||||
import * as BalancerV2Sampler from '../test/generated-artifacts/BalancerV2Sampler.json';
|
||||
import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json';
|
||||
import * as BancorV3Sampler from '../test/generated-artifacts/BancorV3Sampler.json';
|
||||
import * as CompoundSampler from '../test/generated-artifacts/CompoundSampler.json';
|
||||
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
|
||||
import * as DODOV2Sampler from '../test/generated-artifacts/DODOV2Sampler.json';
|
||||
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
|
||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||
import * as FakeTaker from '../test/generated-artifacts/FakeTaker.json';
|
||||
import * as GMXSampler from '../test/generated-artifacts/GMXSampler.json';
|
||||
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
||||
import * as IBalancerV2Vault from '../test/generated-artifacts/IBalancerV2Vault.json';
|
||||
import * as IBancor from '../test/generated-artifacts/IBancor.json';
|
||||
import * as IBancorV3 from '../test/generated-artifacts/IBancorV3.json';
|
||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||
import * as IGMX from '../test/generated-artifacts/IGMX.json';
|
||||
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
|
||||
import * as IMStable from '../test/generated-artifacts/IMStable.json';
|
||||
import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json';
|
||||
import * as IPlatypus from '../test/generated-artifacts/IPlatypus.json';
|
||||
import * as IShell from '../test/generated-artifacts/IShell.json';
|
||||
import * as ISmoothy from '../test/generated-artifacts/ISmoothy.json';
|
||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
||||
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
|
||||
import * as KyberDmmSampler from '../test/generated-artifacts/KyberDmmSampler.json';
|
||||
import * as KyberSampler from '../test/generated-artifacts/KyberSampler.json';
|
||||
import * as LidoSampler from '../test/generated-artifacts/LidoSampler.json';
|
||||
import * as LiquidityProviderSampler from '../test/generated-artifacts/LiquidityProviderSampler.json';
|
||||
import * as MakerPSMSampler from '../test/generated-artifacts/MakerPSMSampler.json';
|
||||
import * as MooniswapSampler from '../test/generated-artifacts/MooniswapSampler.json';
|
||||
import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json';
|
||||
import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json';
|
||||
import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json';
|
||||
import * as PlatypusSampler from '../test/generated-artifacts/PlatypusSampler.json';
|
||||
import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json';
|
||||
import * as ShellSampler from '../test/generated-artifacts/ShellSampler.json';
|
||||
import * as SmoothySampler from '../test/generated-artifacts/SmoothySampler.json';
|
||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
|
||||
import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json';
|
||||
import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json';
|
||||
import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json';
|
||||
import * as UniswapV2Sampler from '../test/generated-artifacts/UniswapV2Sampler.json';
|
||||
import * as UniswapV3Sampler from '../test/generated-artifacts/UniswapV3Sampler.json';
|
||||
import * as UtilitySampler from '../test/generated-artifacts/UtilitySampler.json';
|
||||
import * as VelodromeSampler from '../test/generated-artifacts/VelodromeSampler.json';
|
||||
export const artifacts = {
|
||||
ApproximateBuys: ApproximateBuys as ContractArtifact,
|
||||
BalanceChecker: BalanceChecker as ContractArtifact,
|
||||
BalancerSampler: BalancerSampler as ContractArtifact,
|
||||
BalancerV2BatchSampler: BalancerV2BatchSampler as ContractArtifact,
|
||||
BalancerV2Common: BalancerV2Common as ContractArtifact,
|
||||
BalancerV2Sampler: BalancerV2Sampler as ContractArtifact,
|
||||
BancorSampler: BancorSampler as ContractArtifact,
|
||||
BancorV3Sampler: BancorV3Sampler as ContractArtifact,
|
||||
CompoundSampler: CompoundSampler as ContractArtifact,
|
||||
CurveSampler: CurveSampler as ContractArtifact,
|
||||
DODOSampler: DODOSampler as ContractArtifact,
|
||||
DODOV2Sampler: DODOV2Sampler as ContractArtifact,
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
FakeTaker: FakeTaker as ContractArtifact,
|
||||
GMXSampler: GMXSampler as ContractArtifact,
|
||||
KyberDmmSampler: KyberDmmSampler as ContractArtifact,
|
||||
KyberSampler: KyberSampler as ContractArtifact,
|
||||
LidoSampler: LidoSampler as ContractArtifact,
|
||||
LiquidityProviderSampler: LiquidityProviderSampler as ContractArtifact,
|
||||
MStableSampler: MStableSampler as ContractArtifact,
|
||||
MakerPSMSampler: MakerPSMSampler as ContractArtifact,
|
||||
MooniswapSampler: MooniswapSampler as ContractArtifact,
|
||||
MultiBridgeSampler: MultiBridgeSampler as ContractArtifact,
|
||||
NativeOrderSampler: NativeOrderSampler as ContractArtifact,
|
||||
PlatypusSampler: PlatypusSampler as ContractArtifact,
|
||||
SamplerUtils: SamplerUtils as ContractArtifact,
|
||||
ShellSampler: ShellSampler as ContractArtifact,
|
||||
SmoothySampler: SmoothySampler as ContractArtifact,
|
||||
@@ -76,18 +84,20 @@ export const artifacts = {
|
||||
UniswapV2Sampler: UniswapV2Sampler as ContractArtifact,
|
||||
UniswapV3Sampler: UniswapV3Sampler as ContractArtifact,
|
||||
UtilitySampler: UtilitySampler as ContractArtifact,
|
||||
VelodromeSampler: VelodromeSampler as ContractArtifact,
|
||||
IBalancer: IBalancer as ContractArtifact,
|
||||
IBalancerV2Vault: IBalancerV2Vault as ContractArtifact,
|
||||
IBancor: IBancor as ContractArtifact,
|
||||
IBancorV3: IBancorV3 as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||
IGMX: IGMX as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
IMooniswap: IMooniswap as ContractArtifact,
|
||||
IMultiBridge: IMultiBridge as ContractArtifact,
|
||||
IPlatypus: IPlatypus as ContractArtifact,
|
||||
IShell: IShell as ContractArtifact,
|
||||
ISmoothy: ISmoothy as ContractArtifact,
|
||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
||||
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
|
||||
};
|
||||
|
@@ -21,8 +21,8 @@ const GAS_PRICE = new BigNumber(50e9); // 50 gwei
|
||||
const NATIVE_ORDER_FEE = new BigNumber(220e3); // 220K gas
|
||||
|
||||
// DEX samples to fill in MarketSideLiquidity
|
||||
const kyberSample1: DexSample = {
|
||||
source: ERC20BridgeSource.Kyber,
|
||||
const curveSample: DexSample = {
|
||||
source: ERC20BridgeSource.Curve,
|
||||
input: new BigNumber(10000),
|
||||
output: new BigNumber(10001),
|
||||
fillData: {},
|
||||
@@ -33,7 +33,7 @@ const uniswapSample1: DexSample = {
|
||||
output: new BigNumber(10004),
|
||||
fillData: {},
|
||||
};
|
||||
const dexQuotes: DexSample[] = [kyberSample1, uniswapSample1];
|
||||
const dexQuotes: DexSample[] = [curveSample, uniswapSample1];
|
||||
|
||||
const feeSchedule = {
|
||||
[ERC20BridgeSource.Native]: _.constant(GAS_PRICE.times(NATIVE_ORDER_FEE)),
|
||||
@@ -66,6 +66,7 @@ const buyMarketSideLiquidity: MarketSideLiquidity = {
|
||||
},
|
||||
quoteSourceFilters: new SourceFilters(),
|
||||
isRfqSupported: false,
|
||||
blockNumber: 1337420,
|
||||
};
|
||||
|
||||
const sellMarketSideLiquidity: MarketSideLiquidity = {
|
||||
@@ -87,6 +88,7 @@ const sellMarketSideLiquidity: MarketSideLiquidity = {
|
||||
},
|
||||
quoteSourceFilters: new SourceFilters(),
|
||||
isRfqSupported: false,
|
||||
blockNumber: 1337420,
|
||||
};
|
||||
|
||||
describe('getComparisonPrices', async () => {
|
||||
|
298
packages/asset-swapper/test/contracts/bridge_adapter_test.ts
Normal file
298
packages/asset-swapper/test/contracts/bridge_adapter_test.ts
Normal file
@@ -0,0 +1,298 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { blockchainTests, constants, describe, expect } from '@0x/contracts-test-utils';
|
||||
import {
|
||||
artifacts as zeroExArtifacts,
|
||||
AvalancheBridgeAdapterContract,
|
||||
BSCBridgeAdapterContract,
|
||||
CeloBridgeAdapterContract,
|
||||
EthereumBridgeAdapterContract,
|
||||
FantomBridgeAdapterContract,
|
||||
OptimismBridgeAdapterContract,
|
||||
PolygonBridgeAdapterContract,
|
||||
} from '@0x/contracts-zero-ex';
|
||||
|
||||
import { BUY_SOURCE_FILTER_BY_CHAIN_ID, ERC20BridgeSource, SELL_SOURCE_FILTER_BY_CHAIN_ID } from '../../src';
|
||||
import { getErc20BridgeSourceToBridgeSource } from '../../src/utils/market_operation_utils/orders';
|
||||
|
||||
blockchainTests('Bridge adapter source compatibility tests', env => {
|
||||
describe('Avalanche', () => {
|
||||
let adapter: AvalancheBridgeAdapterContract;
|
||||
before(async () => {
|
||||
adapter = await AvalancheBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
zeroExArtifacts.AvalancheBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
zeroExArtifacts,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
it('sell sources', async () => {
|
||||
const sellSources = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Avalanche].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
sellSources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('buy sources', async () => {
|
||||
const buySources = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Avalanche].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
buySources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('BSC', () => {
|
||||
let adapter: BSCBridgeAdapterContract;
|
||||
before(async () => {
|
||||
adapter = await BSCBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
zeroExArtifacts.BSCBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
zeroExArtifacts,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
it('sell sources', async () => {
|
||||
const sellSources = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.BSC].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
sellSources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('buy sources', async () => {
|
||||
const buySources = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.BSC].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
buySources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Celo', () => {
|
||||
let adapter: CeloBridgeAdapterContract;
|
||||
before(async () => {
|
||||
adapter = await CeloBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
zeroExArtifacts.CeloBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
zeroExArtifacts,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
it('sell sources', async () => {
|
||||
const sellSources = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Celo].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
sellSources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('buy sources', async () => {
|
||||
const buySources = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Celo].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
buySources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Ethereum', () => {
|
||||
let adapter: EthereumBridgeAdapterContract;
|
||||
before(async () => {
|
||||
adapter = await EthereumBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
zeroExArtifacts.EthereumBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
zeroExArtifacts,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
it('sell sources', async () => {
|
||||
const sellSources = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
sellSources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('buy sources', async () => {
|
||||
const buySources = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
buySources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Fantom', () => {
|
||||
let adapter: FantomBridgeAdapterContract;
|
||||
before(async () => {
|
||||
adapter = await FantomBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
zeroExArtifacts.FantomBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
zeroExArtifacts,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
it('sell sources', async () => {
|
||||
const sellSources = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Fantom].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
sellSources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('buy sources', async () => {
|
||||
const buySources = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Fantom].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
buySources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Optimism', () => {
|
||||
let adapter: OptimismBridgeAdapterContract;
|
||||
before(async () => {
|
||||
adapter = await OptimismBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
zeroExArtifacts.OptimismBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
zeroExArtifacts,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
it('sell sources', async () => {
|
||||
const sellSources = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Optimism].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
sellSources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('buy sources', async () => {
|
||||
const buySources = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Optimism].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
buySources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Polygon', () => {
|
||||
let adapter: PolygonBridgeAdapterContract;
|
||||
before(async () => {
|
||||
adapter = await PolygonBridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
zeroExArtifacts.PolygonBridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
zeroExArtifacts,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
it('sell sources', async () => {
|
||||
const sellSources = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Polygon].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
sellSources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('buy sources', async () => {
|
||||
const buySources = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Polygon].exclude([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
]).sources;
|
||||
return Promise.all(
|
||||
buySources.map(async source => {
|
||||
const isSupported = await adapter
|
||||
.isSupportedSource(getErc20BridgeSourceToBridgeSource(source))
|
||||
.callAsync();
|
||||
expect(isSupported, `${source} is not supported`).to.be.true();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,9 +1,7 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { blockchainTests, describe, expect, toBaseUnitAmount, Web3ProviderEngine } from '@0x/contracts-test-utils';
|
||||
import { RPCSubprovider } from '@0x/subproviders';
|
||||
import { BigNumber, NULL_BYTES, providerUtils } from '@0x/utils';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
|
||||
import { KYBER_CONFIG_BY_CHAIN_ID, MAINNET_TOKENS } from '../../src/utils/market_operation_utils/constants';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { ERC20BridgeSamplerContract } from '../wrappers';
|
||||
|
||||
@@ -79,60 +77,4 @@ blockchainTests.skip('Mainnet Sampler Tests', env => {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Kyber', () => {
|
||||
const WETH = MAINNET_TOKENS.WETH;
|
||||
const DAI = MAINNET_TOKENS.DAI;
|
||||
const USDC = MAINNET_TOKENS.USDC;
|
||||
const RESERVE_OFFSET = new BigNumber(0);
|
||||
const KYBER_OPTS = {
|
||||
...KYBER_CONFIG_BY_CHAIN_ID[ChainId.Mainnet],
|
||||
reserveOffset: RESERVE_OFFSET,
|
||||
hint: NULL_BYTES,
|
||||
};
|
||||
describe('sampleSellsFromKyberNetwork()', () => {
|
||||
it('samples sells from Kyber DAI->WETH', async () => {
|
||||
const [, samples] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_OPTS, DAI, WETH, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
it('samples sells from Kyber WETH->DAI', async () => {
|
||||
const [, samples] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_OPTS, WETH, DAI, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
it('samples sells from Kyber DAI->USDC', async () => {
|
||||
const [, samples] = await testContract
|
||||
.sampleSellsFromKyberNetwork(KYBER_OPTS, DAI, USDC, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleBuysFromKyber()', () => {
|
||||
it('samples buys from Kyber WETH->DAI', async () => {
|
||||
// From ETH to DAI
|
||||
// I want to buy 1 DAI
|
||||
const [, samples] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_OPTS, WETH, DAI, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
|
||||
it('samples buys from Kyber DAI->WETH', async () => {
|
||||
// From USDC to DAI
|
||||
// I want to buy 1 WETH
|
||||
const [, samples] = await testContract
|
||||
.sampleBuysFromKyberNetwork(KYBER_OPTS, DAI, WETH, [toBaseUnitAmount(1)])
|
||||
.callAsync({ overrides });
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user