Compare commits
17 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
08e1c5109f | ||
|
6f7a843742 | ||
|
c9c9615bb5 | ||
|
f98609686d | ||
|
5b8bbc34e8 | ||
|
49cb00a9ab | ||
|
74b240fb88 | ||
|
514f9d2621 | ||
|
fa78d1092a | ||
|
297342092b | ||
|
076f263a86 | ||
|
0c56207abc | ||
|
23953d8a5a | ||
|
c6919eb25a | ||
|
d509604b52 | ||
|
a74a3450eb | ||
|
72c5399b9d |
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "3.7.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "3.7.6",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.7.7 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.6 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.7.6",
|
||||
"version": "3.7.7",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,10 +52,10 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contract-wrappers": "^13.12.3",
|
||||
"@0x/contract-wrappers": "^13.13.0",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -80,11 +80,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-erc1155": "^2.1.24",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-erc721": "^3.1.24",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/contracts-erc1155": "^2.1.25",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-erc721": "^3.1.25",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/types": "^3.3.1",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
"@0x/utils": "^6.2.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "1.1.25",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "1.1.24",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.25 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.24 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-broker",
|
||||
"version": "1.1.24",
|
||||
"version": "1.1.25",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,14 +52,14 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-erc721": "^3.1.24",
|
||||
"@0x/contracts-exchange": "^3.2.25",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-erc721": "^3.1.25",
|
||||
"@0x/contracts-exchange": "^3.2.26",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -85,7 +85,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
"@0x/utils": "^6.2.0",
|
||||
"ethereum-types": "^3.4.0"
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "3.1.26",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "3.1.25",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.26 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.25 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.1.25",
|
||||
"version": "3.1.26",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,12 +53,12 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.23",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-dev-utils": "^1.3.24",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -84,10 +84,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.21",
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contract-addresses": "^5.10.0",
|
||||
"@0x/contracts-exchange": "^3.2.25",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contract-addresses": "^5.11.0",
|
||||
"@0x/contracts-exchange": "^3.2.26",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/json-schemas": "^5.4.1",
|
||||
"@0x/types": "^3.3.1",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "1.3.24",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "1.3.23",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.3.24 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.23 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.3.23",
|
||||
"version": "1.3.24",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -43,10 +43,10 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/assert": "^3.0.21",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "2.1.25",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "2.1.24",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.1.25 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.24 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.1.24",
|
||||
"version": "2.1.25",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,7 +54,7 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -81,7 +81,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/utils": "^6.2.0",
|
||||
"@0x/web3-wrapper": "^7.4.1",
|
||||
"lodash": "^4.17.11"
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "3.3.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "3.3.3",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.3.4 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.3 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.3.3",
|
||||
"version": "3.3.4",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,8 +53,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "3.1.25",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "3.1.24",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.25 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.24 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.1.24",
|
||||
"version": "3.1.25",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,8 +54,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "4.2.26",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "4.2.25",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.26 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.25 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.2.25",
|
||||
"version": "4.2.26",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,18 +53,18 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.23",
|
||||
"@0x/contracts-erc1155": "^2.1.24",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-erc721": "^3.1.24",
|
||||
"@0x/contracts-exchange": "^3.2.25",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-dev-utils": "^1.3.24",
|
||||
"@0x/contracts-erc1155": "^2.1.25",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-erc721": "^3.1.25",
|
||||
"@0x/contracts-exchange": "^3.2.26",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "4.3.25",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "4.3.24",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.3.25 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.24 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.3.24",
|
||||
"version": "4.3.25",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -81,9 +81,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/types": "^3.3.1",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
"@0x/utils": "^6.2.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "3.2.26",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "3.2.25",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.26 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.25 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.2.25",
|
||||
"version": "3.2.26",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,13 +53,13 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-multisig": "^4.1.25",
|
||||
"@0x/contracts-staking": "^2.0.32",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-multisig": "^4.1.26",
|
||||
"@0x/contracts-staking": "^2.0.33",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -89,11 +89,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-dev-utils": "^1.3.23",
|
||||
"@0x/contracts-erc1155": "^2.1.24",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-erc721": "^3.1.24",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/contracts-dev-utils": "^1.3.24",
|
||||
"@0x/contracts-erc1155": "^2.1.25",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-erc721": "^3.1.25",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/utils": "^6.2.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "6.2.20",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "6.2.19",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.2.20 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.2.19 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "6.2.19",
|
||||
"version": "6.2.20",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,16 +53,16 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.23",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-erc721": "^3.1.24",
|
||||
"@0x/contracts-exchange": "^3.2.25",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-dev-utils": "^1.3.24",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-erc721": "^3.1.25",
|
||||
"@0x/contracts-exchange": "^3.2.26",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -91,7 +91,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
"ethereum-types": "^3.4.0"
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-integrations",
|
||||
"version": "2.7.26",
|
||||
"version": "2.7.27",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
@@ -53,21 +53,21 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contract-addresses": "^5.10.0",
|
||||
"@0x/contract-wrappers": "^13.12.3",
|
||||
"@0x/contracts-broker": "^1.1.24",
|
||||
"@0x/contracts-coordinator": "^3.1.25",
|
||||
"@0x/contracts-dev-utils": "^1.3.23",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.25",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/contracts-extensions": "^6.2.19",
|
||||
"@0x/contract-addresses": "^5.11.0",
|
||||
"@0x/contract-wrappers": "^13.13.0",
|
||||
"@0x/contracts-broker": "^1.1.25",
|
||||
"@0x/contracts-coordinator": "^3.1.26",
|
||||
"@0x/contracts-dev-utils": "^1.3.24",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.26",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/contracts-extensions": "^6.2.20",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/coordinator-server": "^1.0.5",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/migrations": "^6.6.0",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/protocol-utils": "^1.2.0",
|
||||
"@0x/migrations": "^7.0.0",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/protocol-utils": "^1.3.0",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/web3-wrapper": "^7.4.1",
|
||||
@@ -93,17 +93,17 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/asset-swapper": "^6.0.0",
|
||||
"@0x/asset-swapper": "^6.1.0",
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-erc1155": "^2.1.24",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-erc721": "^3.1.24",
|
||||
"@0x/contracts-exchange": "^3.2.25",
|
||||
"@0x/contracts-multisig": "^4.1.25",
|
||||
"@0x/contracts-staking": "^2.0.32",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-zero-ex": "^0.18.2",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-erc1155": "^2.1.25",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-erc721": "^3.1.25",
|
||||
"@0x/contracts-exchange": "^3.2.26",
|
||||
"@0x/contracts-multisig": "^4.1.26",
|
||||
"@0x/contracts-staking": "^2.0.33",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-zero-ex": "^0.19.0",
|
||||
"@0x/subproviders": "^6.4.1",
|
||||
"@0x/types": "^3.3.1",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "4.1.26",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "4.1.25",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.26 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.25 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-multisig",
|
||||
"version": "4.1.25",
|
||||
"version": "4.1.26",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,11 +50,11 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "2.0.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "2.0.32",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.33 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.32 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-staking",
|
||||
"version": "2.0.32",
|
||||
"version": "2.0.33",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,14 +54,14 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.23",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-dev-utils": "^1.3.24",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
"@0x/utils": "^6.2.0",
|
||||
"ethereum-types": "^3.4.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "5.3.22",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "5.3.21",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.3.22 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.3.21 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.3.21",
|
||||
"version": "5.3.22",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,10 +44,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.21",
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contract-addresses": "^5.10.0",
|
||||
"@0x/contract-addresses": "^5.11.0",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/json-schemas": "^5.4.1",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/sol-coverage": "^4.0.29",
|
||||
"@0x/sol-profiler": "^4.1.19",
|
||||
"@0x/sol-trace": "^3.0.29",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "1.0.1",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.2 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-treasury",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -47,12 +47,12 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.13",
|
||||
"@0x/contract-addresses": "^5.10.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contract-addresses": "^5.11.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-gen": "^2.0.24",
|
||||
"@0x/contracts-staking": "^2.0.32",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-staking": "^2.0.33",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/sol-compiler": "^4.4.1",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -73,7 +73,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.14",
|
||||
"@0x/protocol-utils": "^1.2.0",
|
||||
"@0x/protocol-utils": "^1.3.0",
|
||||
"@0x/subproviders": "^6.2.3",
|
||||
"@0x/types": "^3.3.1",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "4.7.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "4.7.3",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.7.4 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.7.3 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.7.3",
|
||||
"version": "4.7.4",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,9 +52,9 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.3.1",
|
||||
|
@@ -1,4 +1,34 @@
|
||||
[
|
||||
{
|
||||
"version": "0.19.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `CurveLiquidityProvider` and misc refactors",
|
||||
"pr": 127
|
||||
},
|
||||
{
|
||||
"note": "Export `CurveLiquidityProviderContract`",
|
||||
"pr": 144
|
||||
},
|
||||
{
|
||||
"note": "Add `DodoV2`",
|
||||
"pr": 152
|
||||
},
|
||||
{
|
||||
"note": "Add `Linkswap`",
|
||||
"pr": 153
|
||||
},
|
||||
{
|
||||
"note": "refund ETH with no gas limit in FQT",
|
||||
"pr": 155
|
||||
},
|
||||
{
|
||||
"note": "Added an opt-in `PositiveSlippageAffiliateFee`",
|
||||
"pr": 101
|
||||
}
|
||||
],
|
||||
"timestamp": 1614141718
|
||||
},
|
||||
{
|
||||
"version": "0.18.2",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.19.0 - _February 24, 2021_
|
||||
|
||||
* Add `CurveLiquidityProvider` and misc refactors (#127)
|
||||
* Export `CurveLiquidityProviderContract` (#144)
|
||||
* Add `DodoV2` (#152)
|
||||
* Add `Linkswap` (#153)
|
||||
* refund ETH with no gas limit in FQT (#155)
|
||||
* Added an opt-in `PositiveSlippageAffiliateFee` (#101)
|
||||
|
||||
## v0.18.2 - _February 10, 2021_
|
||||
|
||||
* Update FQT for v4 native orders (#104)
|
||||
|
@@ -20,6 +20,9 @@
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "../vendor/ILiquidityProvider.sol";
|
||||
|
||||
|
||||
interface ILiquidityProviderSandbox {
|
||||
|
||||
@@ -32,9 +35,9 @@ interface ILiquidityProviderSandbox {
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForToken(
|
||||
address provider,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
ILiquidityProvider provider,
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -49,8 +52,8 @@ interface ILiquidityProviderSandbox {
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellEthForToken(
|
||||
address provider,
|
||||
address outputToken,
|
||||
ILiquidityProvider provider,
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -65,8 +68,8 @@ interface ILiquidityProviderSandbox {
|
||||
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForEth(
|
||||
address provider,
|
||||
address inputToken,
|
||||
ILiquidityProvider provider,
|
||||
IERC20TokenV06 inputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
|
@@ -17,6 +17,7 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibOwnableRichErrorsV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "../vendor/ILiquidityProvider.sol";
|
||||
import "../vendor/v3/IERC20Bridge.sol";
|
||||
import "./ILiquidityProviderSandbox.sol";
|
||||
@@ -58,9 +59,9 @@ contract LiquidityProviderSandbox is
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForToken(
|
||||
address provider,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
ILiquidityProvider provider,
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -69,7 +70,7 @@ contract LiquidityProviderSandbox is
|
||||
onlyOwner
|
||||
override
|
||||
{
|
||||
ILiquidityProvider(provider).sellTokenForToken(
|
||||
provider.sellTokenForToken(
|
||||
inputToken,
|
||||
outputToken,
|
||||
recipient,
|
||||
@@ -86,8 +87,8 @@ contract LiquidityProviderSandbox is
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellEthForToken(
|
||||
address provider,
|
||||
address outputToken,
|
||||
ILiquidityProvider provider,
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -96,7 +97,7 @@ contract LiquidityProviderSandbox is
|
||||
onlyOwner
|
||||
override
|
||||
{
|
||||
ILiquidityProvider(provider).sellEthForToken(
|
||||
provider.sellEthForToken(
|
||||
outputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
@@ -112,8 +113,8 @@ contract LiquidityProviderSandbox is
|
||||
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForEth(
|
||||
address provider,
|
||||
address inputToken,
|
||||
ILiquidityProvider provider,
|
||||
IERC20TokenV06 inputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -122,7 +123,7 @@ contract LiquidityProviderSandbox is
|
||||
onlyOwner
|
||||
override
|
||||
{
|
||||
ILiquidityProvider(provider).sellTokenForEth(
|
||||
provider.sellTokenForEth(
|
||||
inputToken,
|
||||
payable(recipient),
|
||||
minBuyAmount,
|
||||
|
@@ -20,10 +20,23 @@
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "../vendor/ILiquidityProvider.sol";
|
||||
|
||||
|
||||
/// @dev Feature to swap directly with an on-chain liquidity provider.
|
||||
interface ILiquidityProviderFeature {
|
||||
|
||||
/// @dev Event for data pipeline.
|
||||
event LiquidityProviderSwap(
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
ILiquidityProvider provider,
|
||||
address recipient
|
||||
);
|
||||
|
||||
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
|
||||
/// at the given `provider` address.
|
||||
/// @param inputToken The token being sold.
|
||||
@@ -38,9 +51,9 @@ interface ILiquidityProviderFeature {
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellToLiquidityProvider(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address payable provider,
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
ILiquidityProvider provider,
|
||||
address recipient,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount,
|
||||
|
@@ -23,12 +23,14 @@ pragma experimental ABIEncoderV2;
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "../errors/LibLiquidityProviderRichErrors.sol";
|
||||
import "../external/ILiquidityProviderSandbox.sol";
|
||||
import "../external/LiquidityProviderSandbox.sol";
|
||||
import "../fixins/FixinCommon.sol";
|
||||
import "../fixins/FixinTokenSpender.sol";
|
||||
import "../migrations/LibMigrate.sol";
|
||||
import "../transformers/LibERC20Transformer.sol";
|
||||
import "./IFeature.sol";
|
||||
import "./ILiquidityProviderFeature.sol";
|
||||
|
||||
@@ -45,23 +47,11 @@ contract LiquidityProviderFeature is
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "LiquidityProviderFeature";
|
||||
/// @dev Version of this feature.
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 2);
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 3);
|
||||
|
||||
/// @dev ETH pseudo-token address.
|
||||
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev The sandbox contract address.
|
||||
ILiquidityProviderSandbox public immutable sandbox;
|
||||
|
||||
/// @dev Event for data pipeline.
|
||||
event LiquidityProviderSwap(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address provider,
|
||||
address recipient
|
||||
);
|
||||
|
||||
constructor(LiquidityProviderSandbox sandbox_, bytes32 greedyTokensBloomFilter)
|
||||
public
|
||||
FixinCommon()
|
||||
@@ -95,9 +85,9 @@ contract LiquidityProviderFeature is
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellToLiquidityProvider(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address payable provider,
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
ILiquidityProvider provider,
|
||||
address recipient,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount,
|
||||
@@ -114,21 +104,21 @@ contract LiquidityProviderFeature is
|
||||
|
||||
// Forward all attached ETH to the provider.
|
||||
if (msg.value > 0) {
|
||||
provider.transfer(msg.value);
|
||||
payable(address(provider)).transfer(msg.value);
|
||||
}
|
||||
|
||||
if (inputToken != ETH_TOKEN_ADDRESS) {
|
||||
if (!LibERC20Transformer.isTokenETH(inputToken)) {
|
||||
// Transfer input ERC20 tokens to the provider.
|
||||
_transferERC20Tokens(
|
||||
IERC20TokenV06(inputToken),
|
||||
inputToken,
|
||||
msg.sender,
|
||||
provider,
|
||||
address(provider),
|
||||
sellAmount
|
||||
);
|
||||
}
|
||||
|
||||
if (inputToken == ETH_TOKEN_ADDRESS) {
|
||||
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
|
||||
if (LibERC20Transformer.isTokenETH(inputToken)) {
|
||||
uint256 balanceBefore = outputToken.balanceOf(recipient);
|
||||
sandbox.executeSellEthForToken(
|
||||
provider,
|
||||
outputToken,
|
||||
@@ -137,7 +127,7 @@ contract LiquidityProviderFeature is
|
||||
auxiliaryData
|
||||
);
|
||||
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
|
||||
} else if (outputToken == ETH_TOKEN_ADDRESS) {
|
||||
} else if (LibERC20Transformer.isTokenETH(outputToken)) {
|
||||
uint256 balanceBefore = recipient.balance;
|
||||
sandbox.executeSellTokenForEth(
|
||||
provider,
|
||||
@@ -148,7 +138,7 @@ contract LiquidityProviderFeature is
|
||||
);
|
||||
boughtAmount = recipient.balance.safeSub(balanceBefore);
|
||||
} else {
|
||||
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
|
||||
uint256 balanceBefore = outputToken.balanceOf(recipient);
|
||||
sandbox.executeSellTokenForToken(
|
||||
provider,
|
||||
inputToken,
|
||||
@@ -157,14 +147,14 @@ contract LiquidityProviderFeature is
|
||||
minBuyAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
|
||||
boughtAmount = outputToken.balanceOf(recipient).safeSub(balanceBefore);
|
||||
}
|
||||
|
||||
if (boughtAmount < minBuyAmount) {
|
||||
LibLiquidityProviderRichErrors.LiquidityProviderIncompleteSellError(
|
||||
provider,
|
||||
outputToken,
|
||||
inputToken,
|
||||
address(provider),
|
||||
address(outputToken),
|
||||
address(inputToken),
|
||||
sellAmount,
|
||||
boughtAmount,
|
||||
minBuyAmount
|
||||
|
@@ -0,0 +1,208 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
import "../transformers/LibERC20Transformer.sol";
|
||||
import "../vendor/ILiquidityProvider.sol";
|
||||
|
||||
|
||||
contract CurveLiquidityProvider is
|
||||
ILiquidityProvider
|
||||
{
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
struct CurveData {
|
||||
address curveAddress;
|
||||
bytes4 exchangeFunctionSelector;
|
||||
int128 fromCoinIdx;
|
||||
int128 toCoinIdx;
|
||||
}
|
||||
|
||||
/// @dev This contract must be payable because takers can transfer funds
|
||||
/// in prior to calling the swap function.
|
||||
receive() external payable {}
|
||||
|
||||
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
|
||||
/// to sell must be transferred to the contract prior to calling this
|
||||
/// function to trigger the trade.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellTokenForToken(
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
override
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
require(
|
||||
!LibERC20Transformer.isTokenETH(inputToken)
|
||||
&& !LibERC20Transformer.isTokenETH(outputToken),
|
||||
"CurveLiquidityProvider/INVALID_ARGS"
|
||||
);
|
||||
boughtAmount = _executeSwap(
|
||||
inputToken,
|
||||
outputToken,
|
||||
minBuyAmount,
|
||||
abi.decode(auxiliaryData, (CurveData))
|
||||
);
|
||||
// Every pool contract currently checks this but why not.
|
||||
require(boughtAmount >= minBuyAmount, "CurveLiquidityProvider/UNDERBOUGHT");
|
||||
outputToken.compatTransfer(recipient, boughtAmount);
|
||||
}
|
||||
|
||||
/// @dev Trades ETH for token. ETH must either be attached to this function
|
||||
/// call or sent to the contract prior to calling this function to
|
||||
/// trigger the trade.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellEthForToken(
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
payable
|
||||
override
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
require(
|
||||
!LibERC20Transformer.isTokenETH(outputToken),
|
||||
"CurveLiquidityProvider/INVALID_ARGS"
|
||||
);
|
||||
boughtAmount = _executeSwap(
|
||||
LibERC20Transformer.ETH_TOKEN,
|
||||
outputToken,
|
||||
minBuyAmount,
|
||||
abi.decode(auxiliaryData, (CurveData))
|
||||
);
|
||||
// Every pool contract currently checks this but why not.
|
||||
require(boughtAmount >= minBuyAmount, "CurveLiquidityProvider/UNDERBOUGHT");
|
||||
outputToken.compatTransfer(recipient, boughtAmount);
|
||||
}
|
||||
|
||||
/// @dev Trades token for ETH. The token must be sent to the contract prior
|
||||
/// to calling this function to trigger the trade.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of ETH bought.
|
||||
function sellTokenForEth(
|
||||
IERC20TokenV06 inputToken,
|
||||
address payable recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
override
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
require(
|
||||
!LibERC20Transformer.isTokenETH(inputToken),
|
||||
"CurveLiquidityProvider/INVALID_ARGS"
|
||||
);
|
||||
boughtAmount = _executeSwap(
|
||||
inputToken,
|
||||
LibERC20Transformer.ETH_TOKEN,
|
||||
minBuyAmount,
|
||||
abi.decode(auxiliaryData, (CurveData))
|
||||
);
|
||||
// Every pool contract currently checks this but why not.
|
||||
require(boughtAmount >= minBuyAmount, "CurveLiquidityProvider/UNDERBOUGHT");
|
||||
recipient.transfer(boughtAmount);
|
||||
}
|
||||
|
||||
/// @dev Quotes the amount of `outputToken` that would be obtained by
|
||||
/// selling `sellAmount` of `inputToken`.
|
||||
function getSellQuote(
|
||||
IERC20TokenV06 /* inputToken */,
|
||||
IERC20TokenV06 /* outputToken */,
|
||||
uint256 /* sellAmount */
|
||||
)
|
||||
external
|
||||
view
|
||||
override
|
||||
returns (uint256)
|
||||
{
|
||||
revert("CurveLiquidityProvider/NOT_IMPLEMENTED");
|
||||
}
|
||||
|
||||
/// @dev Perform the swap against the curve pool. Handles any combination of
|
||||
/// tokens
|
||||
function _executeSwap(
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
uint256 minBuyAmount,
|
||||
CurveData memory data
|
||||
)
|
||||
private
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
uint256 sellAmount =
|
||||
LibERC20Transformer.getTokenBalanceOf(inputToken, address(this));
|
||||
if (!LibERC20Transformer.isTokenETH(inputToken)) {
|
||||
inputToken.approveIfBelow(data.curveAddress, sellAmount);
|
||||
}
|
||||
|
||||
(bool success, bytes memory resultData) =
|
||||
data.curveAddress.call
|
||||
{ value: LibERC20Transformer.isTokenETH(inputToken) ? sellAmount : 0 }
|
||||
(abi.encodeWithSelector(
|
||||
data.exchangeFunctionSelector,
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
sellAmount,
|
||||
// min dy
|
||||
minBuyAmount
|
||||
));
|
||||
if (!success) {
|
||||
resultData.rrevert();
|
||||
}
|
||||
if (resultData.length == 32) {
|
||||
// Pool returned a boughtAmount
|
||||
boughtAmount = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
// Not all pool contracts return a `boughtAmount`, so we return
|
||||
// our balance of the output token if it wasn't returned.
|
||||
boughtAmount = LibERC20Transformer
|
||||
.getTokenBalanceOf(outputToken, address(this));
|
||||
}
|
||||
}
|
||||
}
|
@@ -273,13 +273,15 @@ contract FillQuoteTransformer is
|
||||
|
||||
// Refund unspent protocol fees.
|
||||
if (state.ethRemaining > 0 && data.refundReceiver != address(0)) {
|
||||
bool transferSuccess;
|
||||
if (data.refundReceiver == REFUND_RECEIVER_TAKER) {
|
||||
context.taker.transfer(state.ethRemaining);
|
||||
(transferSuccess,) = context.taker.call{value: state.ethRemaining}("");
|
||||
} else if (data.refundReceiver == REFUND_RECEIVER_SENDER) {
|
||||
context.sender.transfer(state.ethRemaining);
|
||||
(transferSuccess,) = context.sender.call{value: state.ethRemaining}("");
|
||||
} else {
|
||||
data.refundReceiver.transfer(state.ethRemaining);
|
||||
(transferSuccess,) = data.refundReceiver.call{value: state.ethRemaining}("");
|
||||
}
|
||||
require(transferSuccess, "FillQuoteTransformer/ETHER_TRANSFER_FALIED");
|
||||
}
|
||||
return LibERC20Transformer.TRANSFORMER_SUCCESS;
|
||||
}
|
||||
|
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "../errors/LibTransformERC20RichErrors.sol";
|
||||
import "./Transformer.sol";
|
||||
import "./LibERC20Transformer.sol";
|
||||
|
||||
|
||||
/// @dev A transformer that transfers tokens to arbitrary addresses.
|
||||
contract PositiveSlippageFeeTransformer is
|
||||
Transformer
|
||||
{
|
||||
using LibRichErrorsV06 for bytes;
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibERC20Transformer for IERC20TokenV06;
|
||||
|
||||
/// @dev Information for a single fee.
|
||||
struct TokenFee {
|
||||
// The token to transfer to `recipient`.
|
||||
IERC20TokenV06 token;
|
||||
// Amount of each `token` to transfer to `recipient`.
|
||||
uint256 bestCaseAmount;
|
||||
// Recipient of `token`.
|
||||
address payable recipient;
|
||||
}
|
||||
|
||||
/// @dev Transfers tokens to recipients.
|
||||
/// @param context Context information.
|
||||
/// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`).
|
||||
function transform(TransformContext calldata context)
|
||||
external
|
||||
override
|
||||
returns (bytes4 success)
|
||||
{
|
||||
TokenFee memory fee = abi.decode(context.data, (TokenFee));
|
||||
|
||||
uint256 transformerAmount = LibERC20Transformer.getTokenBalanceOf(fee.token, address(this));
|
||||
if (transformerAmount > fee.bestCaseAmount) {
|
||||
uint256 positiveSlippageAmount = transformerAmount - fee.bestCaseAmount;
|
||||
fee.token.transformerTransfer(fee.recipient, positiveSlippageAmount);
|
||||
}
|
||||
|
||||
return LibERC20Transformer.TRANSFORMER_SUCCESS;
|
||||
}
|
||||
}
|
@@ -28,6 +28,7 @@ import "./mixins/MixinCoFiX.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCryptoCom.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyber.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
import "./mixins/MixinMStable.sol";
|
||||
@@ -46,6 +47,7 @@ contract BridgeAdapter is
|
||||
MixinCurve,
|
||||
MixinCryptoCom,
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyber,
|
||||
MixinMooniswap,
|
||||
MixinMStable,
|
||||
@@ -64,6 +66,7 @@ contract BridgeAdapter is
|
||||
MixinCurve()
|
||||
MixinCryptoCom()
|
||||
MixinDodo()
|
||||
MixinDodoV2()
|
||||
MixinKyber(weth)
|
||||
MixinMooniswap(weth)
|
||||
MixinMStable()
|
||||
@@ -100,7 +103,8 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (order.source == BridgeSource.UNISWAPV2) {
|
||||
} else if (order.source == BridgeSource.UNISWAPV2 ||
|
||||
order.source == BridgeSource.LINKSWAP) {
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
@@ -162,6 +166,12 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (order.source == BridgeSource.DODOV2) {
|
||||
boughtAmount = _tradeDodoV2(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (order.source == BridgeSource.CRYPTOCOM) {
|
||||
boughtAmount = _tradeCryptoCom(
|
||||
buyToken,
|
||||
|
@@ -40,6 +40,8 @@ library BridgeSource {
|
||||
uint256 constant internal SWERVE = 15;
|
||||
uint256 constant internal UNISWAP = 16;
|
||||
uint256 constant internal UNISWAPV2 = 17;
|
||||
uint256 constant internal DODOV2 = 18;
|
||||
uint256 constant internal LINKSWAP = 19;
|
||||
// New sources should be APPENDED to this list, taking the next highest
|
||||
// integer value.
|
||||
}
|
||||
|
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "../IBridgeAdapter.sol";
|
||||
|
||||
|
||||
interface IDODOV2 {
|
||||
function sellBase(address recipient)
|
||||
external
|
||||
returns (uint256);
|
||||
|
||||
function sellQuote(address recipient)
|
||||
external
|
||||
returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract MixinDodoV2 {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeDodoV2(
|
||||
IERC20TokenV06 sellToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(IDODOV2 pool, bool isSellBase) =
|
||||
abi.decode(bridgeData, (IDODOV2, bool));
|
||||
|
||||
// Transfer the tokens into the pool
|
||||
sellToken.compatTransfer(address(pool), sellAmount);
|
||||
|
||||
boughtAmount = isSellBase ?
|
||||
pool.sellBase(address(this))
|
||||
: pool.sellQuote(address(this));
|
||||
}
|
||||
}
|
@@ -47,8 +47,8 @@ contract MixinZeroExBridge {
|
||||
sellAmount
|
||||
);
|
||||
boughtAmount = provider.sellTokenForToken(
|
||||
address(sellToken),
|
||||
address(buyToken),
|
||||
sellToken,
|
||||
buyToken,
|
||||
address(this), // recipient
|
||||
1, // minBuyAmount
|
||||
lpData
|
||||
|
@@ -19,6 +19,9 @@
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
|
||||
|
||||
interface ILiquidityProvider {
|
||||
|
||||
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
|
||||
@@ -31,8 +34,8 @@ interface ILiquidityProvider {
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellTokenForToken(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -49,7 +52,7 @@ interface ILiquidityProvider {
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellEthForToken(
|
||||
address outputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -66,7 +69,7 @@ interface ILiquidityProvider {
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of ETH bought.
|
||||
function sellTokenForEth(
|
||||
address inputToken,
|
||||
IERC20TokenV06 inputToken,
|
||||
address payable recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
@@ -83,8 +86,8 @@ interface ILiquidityProvider {
|
||||
/// @param sellAmount Amount of `inputToken` to sell.
|
||||
/// @return outputTokenAmount Amount of `outputToken` that would be obtained.
|
||||
function getSellQuote(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
|
100
contracts/zero-ex/contracts/test/TestCurve.sol
Normal file
100
contracts/zero-ex/contracts/test/TestCurve.sol
Normal file
@@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "./TestMintableERC20Token.sol";
|
||||
|
||||
contract TestCurve {
|
||||
|
||||
event CurveCalled(
|
||||
uint256 value,
|
||||
bytes4 selector,
|
||||
int128 fromCoinIdx,
|
||||
int128 toCoinIdx,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
);
|
||||
|
||||
// The lower 16 bits of the selector are reserved for flags.
|
||||
bytes4 public constant BASE_SWAP_SELECTOR = 0x12340000;
|
||||
bytes4 public constant RETURN_BOUGHT_AMOUNT_SELECTOR_FLAG = 0x00000001;
|
||||
|
||||
int128 public constant SELL_TOKEN_COIN_IDX = 0;
|
||||
int128 public constant BUY_TOKEN_COIN_IDX = 1;
|
||||
int128 public constant ETH_COIN_IDX = 2;
|
||||
|
||||
uint256 public buyAmount;
|
||||
IERC20TokenV06 public sellToken;
|
||||
TestMintableERC20Token public buyToken;
|
||||
|
||||
constructor(
|
||||
IERC20TokenV06 sellToken_,
|
||||
TestMintableERC20Token buyToken_,
|
||||
uint256 buyAmount_
|
||||
)
|
||||
public
|
||||
payable
|
||||
{
|
||||
sellToken = sellToken_;
|
||||
buyToken = buyToken_;
|
||||
buyAmount = buyAmount_;
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
fallback() external payable {
|
||||
bytes4 selector = abi.decode(msg.data, (bytes4));
|
||||
bool shouldReturnBoughtAmount =
|
||||
(selector & RETURN_BOUGHT_AMOUNT_SELECTOR_FLAG) != 0x0;
|
||||
bytes4 baseSelector = selector & 0xffff0000;
|
||||
require(baseSelector == BASE_SWAP_SELECTOR, "TestCurve/REVERT");
|
||||
(
|
||||
int128 fromCoinIdx,
|
||||
int128 toCoinIdx,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
) = abi.decode(msg.data[4:], (int128, int128, uint256, uint256));
|
||||
if (fromCoinIdx == SELL_TOKEN_COIN_IDX) {
|
||||
sellToken.transferFrom(msg.sender, address(this), sellAmount);
|
||||
}
|
||||
if (toCoinIdx == BUY_TOKEN_COIN_IDX) {
|
||||
buyToken.mint(msg.sender, buyAmount);
|
||||
} else if (toCoinIdx == ETH_COIN_IDX) {
|
||||
msg.sender.transfer(buyAmount);
|
||||
}
|
||||
emit CurveCalled(
|
||||
msg.value,
|
||||
selector,
|
||||
fromCoinIdx,
|
||||
toCoinIdx,
|
||||
sellAmount,
|
||||
minBuyAmount
|
||||
);
|
||||
if (shouldReturnBoughtAmount) {
|
||||
assembly {
|
||||
mstore(0, sload(buyAmount_slot))
|
||||
return(0, 32)
|
||||
}
|
||||
}
|
||||
assembly { return(0, 0) }
|
||||
}
|
||||
}
|
@@ -74,7 +74,7 @@ contract TestLiquidityProvider {
|
||||
bytes calldata // auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount)
|
||||
returns (uint256)
|
||||
{
|
||||
emit SellTokenForToken(
|
||||
inputToken,
|
||||
@@ -98,7 +98,7 @@ contract TestLiquidityProvider {
|
||||
bytes calldata // auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount)
|
||||
returns (uint256)
|
||||
{
|
||||
emit SellEthForToken(
|
||||
outputToken,
|
||||
@@ -121,7 +121,7 @@ contract TestLiquidityProvider {
|
||||
bytes calldata // auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount)
|
||||
returns (uint256)
|
||||
{
|
||||
emit SellTokenForEth(
|
||||
inputToken,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-zero-ex",
|
||||
"version": "0.18.2",
|
||||
"version": "0.19.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -41,9 +41,9 @@
|
||||
"rollback": "node ./lib/scripts/rollback.js"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector",
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|BridgeSource|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|BridgeSource|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -56,12 +56,12 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.19",
|
||||
"@0x/contract-addresses": "^5.10.0",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contract-addresses": "^5.11.0",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/order-utils": "^10.4.16",
|
||||
"@0x/order-utils": "^10.4.17",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -83,7 +83,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/protocol-utils": "^1.2.0",
|
||||
"@0x/protocol-utils": "^1.3.0",
|
||||
"@0x/subproviders": "^6.4.1",
|
||||
"@0x/types": "^3.3.1",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
|
@@ -7,6 +7,7 @@ import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as AffiliateFeeTransformer from '../generated-artifacts/AffiliateFeeTransformer.json';
|
||||
import * as BridgeAdapter from '../generated-artifacts/BridgeAdapter.json';
|
||||
import * as CurveLiquidityProvider from '../generated-artifacts/CurveLiquidityProvider.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';
|
||||
@@ -28,6 +29,7 @@ import * as MetaTransactionsFeature from '../generated-artifacts/MetaTransaction
|
||||
import * as NativeOrdersFeature from '../generated-artifacts/NativeOrdersFeature.json';
|
||||
import * as OwnableFeature from '../generated-artifacts/OwnableFeature.json';
|
||||
import * as PayTakerTransformer from '../generated-artifacts/PayTakerTransformer.json';
|
||||
import * as PositiveSlippageFeeTransformer from '../generated-artifacts/PositiveSlippageFeeTransformer.json';
|
||||
import * as SimpleFunctionRegistryFeature from '../generated-artifacts/SimpleFunctionRegistryFeature.json';
|
||||
import * as TokenSpenderFeature from '../generated-artifacts/TokenSpenderFeature.json';
|
||||
import * as TransformERC20Feature from '../generated-artifacts/TransformERC20Feature.json';
|
||||
@@ -47,6 +49,7 @@ export const artifacts = {
|
||||
ITransformERC20Feature: ITransformERC20Feature as ContractArtifact,
|
||||
FillQuoteTransformer: FillQuoteTransformer as ContractArtifact,
|
||||
PayTakerTransformer: PayTakerTransformer as ContractArtifact,
|
||||
PositiveSlippageFeeTransformer: PositiveSlippageFeeTransformer as ContractArtifact,
|
||||
WethTransformer: WethTransformer as ContractArtifact,
|
||||
OwnableFeature: OwnableFeature as ContractArtifact,
|
||||
SimpleFunctionRegistryFeature: SimpleFunctionRegistryFeature as ContractArtifact,
|
||||
@@ -62,4 +65,5 @@ export const artifacts = {
|
||||
INativeOrdersFeature: INativeOrdersFeature as ContractArtifact,
|
||||
FeeCollectorController: FeeCollectorController as ContractArtifact,
|
||||
FeeCollector: FeeCollector as ContractArtifact,
|
||||
CurveLiquidityProvider: CurveLiquidityProvider as ContractArtifact,
|
||||
};
|
||||
|
@@ -46,6 +46,7 @@ export {
|
||||
IZeroExContract,
|
||||
LogMetadataTransformerContract,
|
||||
PayTakerTransformerContract,
|
||||
PositiveSlippageFeeTransformerContract,
|
||||
WethTransformerContract,
|
||||
ZeroExContract,
|
||||
} from './wrappers';
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
export * from '../generated-wrappers/affiliate_fee_transformer';
|
||||
export * from '../generated-wrappers/bridge_adapter';
|
||||
export * from '../generated-wrappers/curve_liquidity_provider';
|
||||
export * from '../generated-wrappers/fee_collector';
|
||||
export * from '../generated-wrappers/fee_collector_controller';
|
||||
export * from '../generated-wrappers/fill_quote_transformer';
|
||||
@@ -26,6 +27,7 @@ export * from '../generated-wrappers/meta_transactions_feature';
|
||||
export * from '../generated-wrappers/native_orders_feature';
|
||||
export * from '../generated-wrappers/ownable_feature';
|
||||
export * from '../generated-wrappers/pay_taker_transformer';
|
||||
export * from '../generated-wrappers/positive_slippage_fee_transformer';
|
||||
export * from '../generated-wrappers/simple_function_registry_feature';
|
||||
export * from '../generated-wrappers/token_spender_feature';
|
||||
export * from '../generated-wrappers/transform_erc20_feature';
|
||||
|
@@ -10,6 +10,7 @@ import * as AllowanceTarget from '../test/generated-artifacts/AllowanceTarget.js
|
||||
import * as BootstrapFeature from '../test/generated-artifacts/BootstrapFeature.json';
|
||||
import * as BridgeAdapter from '../test/generated-artifacts/BridgeAdapter.json';
|
||||
import * as BridgeSource from '../test/generated-artifacts/BridgeSource.json';
|
||||
import * as CurveLiquidityProvider from '../test/generated-artifacts/CurveLiquidityProvider.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';
|
||||
@@ -77,6 +78,7 @@ import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
|
||||
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
|
||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.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 MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
|
||||
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
|
||||
@@ -90,9 +92,11 @@ import * as NativeOrdersFeature from '../test/generated-artifacts/NativeOrdersFe
|
||||
import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json';
|
||||
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
|
||||
import * as PermissionlessTransformerDeployer from '../test/generated-artifacts/PermissionlessTransformerDeployer.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';
|
||||
import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.json';
|
||||
import * as TestCurve from '../test/generated-artifacts/TestCurve.json';
|
||||
import * as TestDelegateCaller from '../test/generated-artifacts/TestDelegateCaller.json';
|
||||
import * as TestFeeCollectorController from '../test/generated-artifacts/TestFeeCollectorController.json';
|
||||
import * as TestFillQuoteTransformerBridge from '../test/generated-artifacts/TestFillQuoteTransformerBridge.json';
|
||||
@@ -186,6 +190,7 @@ export const artifacts = {
|
||||
FixinProtocolFees: FixinProtocolFees as ContractArtifact,
|
||||
FixinReentrancyGuard: FixinReentrancyGuard as ContractArtifact,
|
||||
FixinTokenSpender: FixinTokenSpender as ContractArtifact,
|
||||
CurveLiquidityProvider: CurveLiquidityProvider as ContractArtifact,
|
||||
FullMigration: FullMigration as ContractArtifact,
|
||||
InitialMigration: InitialMigration as ContractArtifact,
|
||||
LibBootstrap: LibBootstrap as ContractArtifact,
|
||||
@@ -205,6 +210,7 @@ export const artifacts = {
|
||||
LibERC20Transformer: LibERC20Transformer as ContractArtifact,
|
||||
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
|
||||
PayTakerTransformer: PayTakerTransformer as ContractArtifact,
|
||||
PositiveSlippageFeeTransformer: PositiveSlippageFeeTransformer as ContractArtifact,
|
||||
Transformer: Transformer as ContractArtifact,
|
||||
WethTransformer: WethTransformer as ContractArtifact,
|
||||
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
||||
@@ -216,6 +222,7 @@ export const artifacts = {
|
||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
MixinDodo: MixinDodo as ContractArtifact,
|
||||
MixinDodoV2: MixinDodoV2 as ContractArtifact,
|
||||
MixinKyber: MixinKyber as ContractArtifact,
|
||||
MixinMStable: MixinMStable as ContractArtifact,
|
||||
MixinMooniswap: MixinMooniswap as ContractArtifact,
|
||||
@@ -231,6 +238,7 @@ export const artifacts = {
|
||||
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
|
||||
TestBridge: TestBridge as ContractArtifact,
|
||||
TestCallTarget: TestCallTarget as ContractArtifact,
|
||||
TestCurve: TestCurve as ContractArtifact,
|
||||
TestDelegateCaller: TestDelegateCaller as ContractArtifact,
|
||||
TestFeeCollectorController: TestFeeCollectorController as ContractArtifact,
|
||||
TestFillQuoteTransformerBridge: TestFillQuoteTransformerBridge as ContractArtifact,
|
||||
|
294
contracts/zero-ex/test/liqudity-providers/curve_test.ts
Normal file
294
contracts/zero-ex/test/liqudity-providers/curve_test.ts
Normal file
@@ -0,0 +1,294 @@
|
||||
import { blockchainTests, constants, expect, getRandomInteger, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { CurveLiquidityProviderContract, TestCurveContract, TestMintableERC20TokenContract } from '../wrappers';
|
||||
|
||||
blockchainTests.resets('CurveLiquidityProvider feature', env => {
|
||||
let lp: CurveLiquidityProviderContract;
|
||||
let sellToken: TestMintableERC20TokenContract;
|
||||
let buyToken: TestMintableERC20TokenContract;
|
||||
let testCurve: TestCurveContract;
|
||||
let owner: string;
|
||||
let taker: string;
|
||||
const RECIPIENT = hexUtils.random(20);
|
||||
const SELL_AMOUNT = getRandomInteger('1e6', '1e18');
|
||||
const BUY_AMOUNT = getRandomInteger('1e6', '10e18');
|
||||
const REVERTING_SELECTOR = '0xdeaddead';
|
||||
const SWAP_SELECTOR = '0x12340000';
|
||||
const SWAP_WITH_RETURN_SELECTOR = '0x12340001';
|
||||
const ETH_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
|
||||
const SELL_TOKEN_COIN_IDX = 0;
|
||||
const BUY_TOKEN_COIN_IDX = 1;
|
||||
const ETH_COIN_IDX = 2;
|
||||
const { ZERO_AMOUNT } = constants;
|
||||
|
||||
before(async () => {
|
||||
[owner, taker] = await env.getAccountAddressesAsync();
|
||||
[sellToken, buyToken] = await Promise.all(
|
||||
new Array(2)
|
||||
.fill(0)
|
||||
.map(async () =>
|
||||
TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestMintableERC20Token,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
),
|
||||
),
|
||||
);
|
||||
testCurve = await TestCurveContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestCurve,
|
||||
env.provider,
|
||||
{ ...env.txDefaults, value: BUY_AMOUNT },
|
||||
artifacts,
|
||||
sellToken.address,
|
||||
buyToken.address,
|
||||
BUY_AMOUNT,
|
||||
);
|
||||
lp = await CurveLiquidityProviderContract.deployFrom0xArtifactAsync(
|
||||
artifacts.CurveLiquidityProvider,
|
||||
env.provider,
|
||||
{ ...env.txDefaults, from: taker },
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
interface CurveDataFields {
|
||||
curveAddress: string;
|
||||
exchangeFunctionSelector: string;
|
||||
fromCoinIdx: number;
|
||||
toCoinIdx: number;
|
||||
}
|
||||
|
||||
async function fundProviderContractAsync(fromCoinIdx: number, amount: BigNumber = SELL_AMOUNT): Promise<void> {
|
||||
if (fromCoinIdx === SELL_TOKEN_COIN_IDX) {
|
||||
await sellToken.mint(lp.address, SELL_AMOUNT).awaitTransactionSuccessAsync();
|
||||
} else {
|
||||
await env.web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await env.web3Wrapper.sendTransactionAsync({
|
||||
from: taker,
|
||||
to: lp.address,
|
||||
value: SELL_AMOUNT,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function encodeCurveData(fields: Partial<CurveDataFields> = {}): string {
|
||||
const _fields = {
|
||||
curveAddress: testCurve.address,
|
||||
exchangeFunctionSelector: SWAP_SELECTOR,
|
||||
fromCoinIdx: SELL_TOKEN_COIN_IDX,
|
||||
toCoinIdx: BUY_TOKEN_COIN_IDX,
|
||||
...fields,
|
||||
};
|
||||
return hexUtils.concat(
|
||||
hexUtils.leftPad(_fields.curveAddress),
|
||||
hexUtils.rightPad(_fields.exchangeFunctionSelector),
|
||||
hexUtils.leftPad(_fields.fromCoinIdx),
|
||||
hexUtils.leftPad(_fields.toCoinIdx),
|
||||
);
|
||||
}
|
||||
|
||||
it('can swap ERC20->ERC20', async () => {
|
||||
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
|
||||
const call = lp.sellTokenForToken(
|
||||
sellToken.address,
|
||||
buyToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData(),
|
||||
);
|
||||
const boughtAmount = await call.callAsync();
|
||||
const { logs } = await call.awaitTransactionSuccessAsync();
|
||||
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
|
||||
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
value: ZERO_AMOUNT,
|
||||
selector: SWAP_SELECTOR,
|
||||
fromCoinIdx: new BigNumber(SELL_TOKEN_COIN_IDX),
|
||||
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
|
||||
sellAmount: SELL_AMOUNT,
|
||||
minBuyAmount: BUY_AMOUNT,
|
||||
},
|
||||
],
|
||||
'CurveCalled',
|
||||
);
|
||||
});
|
||||
|
||||
it('can swap ERC20->ETH', async () => {
|
||||
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
|
||||
const call = lp.sellTokenForEth(
|
||||
sellToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData({ toCoinIdx: ETH_COIN_IDX }),
|
||||
);
|
||||
const boughtAmount = await call.callAsync();
|
||||
const { logs } = await call.awaitTransactionSuccessAsync();
|
||||
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
|
||||
expect(await env.web3Wrapper.getBalanceInWeiAsync(RECIPIENT)).to.bignumber.eq(BUY_AMOUNT);
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
value: ZERO_AMOUNT,
|
||||
selector: SWAP_SELECTOR,
|
||||
fromCoinIdx: new BigNumber(SELL_TOKEN_COIN_IDX),
|
||||
toCoinIdx: new BigNumber(ETH_COIN_IDX),
|
||||
sellAmount: SELL_AMOUNT,
|
||||
minBuyAmount: BUY_AMOUNT,
|
||||
},
|
||||
],
|
||||
'CurveCalled',
|
||||
);
|
||||
});
|
||||
|
||||
it('can swap ETH->ERC20', async () => {
|
||||
await fundProviderContractAsync(ETH_COIN_IDX);
|
||||
const call = lp.sellEthForToken(
|
||||
buyToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData({ fromCoinIdx: ETH_COIN_IDX }),
|
||||
);
|
||||
const boughtAmount = await call.callAsync();
|
||||
const { logs } = await call.awaitTransactionSuccessAsync();
|
||||
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
|
||||
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
value: SELL_AMOUNT,
|
||||
selector: SWAP_SELECTOR,
|
||||
fromCoinIdx: new BigNumber(ETH_COIN_IDX),
|
||||
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
|
||||
sellAmount: SELL_AMOUNT,
|
||||
minBuyAmount: BUY_AMOUNT,
|
||||
},
|
||||
],
|
||||
'CurveCalled',
|
||||
);
|
||||
});
|
||||
|
||||
it('can swap ETH->ERC20 with attached ETH', async () => {
|
||||
const call = lp.sellEthForToken(
|
||||
buyToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData({ fromCoinIdx: ETH_COIN_IDX }),
|
||||
);
|
||||
const boughtAmount = await call.callAsync({ value: SELL_AMOUNT });
|
||||
const { logs } = await call.awaitTransactionSuccessAsync({ value: SELL_AMOUNT });
|
||||
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
|
||||
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
value: SELL_AMOUNT,
|
||||
selector: SWAP_SELECTOR,
|
||||
fromCoinIdx: new BigNumber(ETH_COIN_IDX),
|
||||
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
|
||||
sellAmount: SELL_AMOUNT,
|
||||
minBuyAmount: BUY_AMOUNT,
|
||||
},
|
||||
],
|
||||
'CurveCalled',
|
||||
);
|
||||
});
|
||||
|
||||
it('can swap with a pool that returns bought amount', async () => {
|
||||
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
|
||||
const call = lp.sellTokenForToken(
|
||||
sellToken.address,
|
||||
buyToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData({ exchangeFunctionSelector: SWAP_WITH_RETURN_SELECTOR }),
|
||||
);
|
||||
const boughtAmount = await call.callAsync();
|
||||
const { logs } = await call.awaitTransactionSuccessAsync();
|
||||
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
|
||||
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
value: ZERO_AMOUNT,
|
||||
selector: SWAP_WITH_RETURN_SELECTOR,
|
||||
fromCoinIdx: new BigNumber(SELL_TOKEN_COIN_IDX),
|
||||
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
|
||||
sellAmount: SELL_AMOUNT,
|
||||
minBuyAmount: BUY_AMOUNT,
|
||||
},
|
||||
],
|
||||
'CurveCalled',
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts if pool reverts', async () => {
|
||||
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
|
||||
const call = lp.sellTokenForToken(
|
||||
sellToken.address,
|
||||
buyToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData({ exchangeFunctionSelector: REVERTING_SELECTOR }),
|
||||
);
|
||||
return expect(call.callAsync()).to.revertWith('TestCurve/REVERT');
|
||||
});
|
||||
|
||||
it('reverts if underbought', async () => {
|
||||
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
|
||||
const call = lp.sellTokenForToken(
|
||||
sellToken.address,
|
||||
buyToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT.plus(1),
|
||||
encodeCurveData(),
|
||||
);
|
||||
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/UNDERBOUGHT');
|
||||
});
|
||||
|
||||
it('reverts if ERC20->ERC20 receives an ETH input token', async () => {
|
||||
await fundProviderContractAsync(ETH_COIN_IDX);
|
||||
const call = lp.sellTokenForToken(
|
||||
ETH_TOKEN_ADDRESS,
|
||||
buyToken.address,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData(),
|
||||
);
|
||||
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
|
||||
});
|
||||
|
||||
it('reverts if ERC20->ERC20 receives an ETH output token', async () => {
|
||||
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
|
||||
const call = lp.sellTokenForToken(
|
||||
sellToken.address,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
RECIPIENT,
|
||||
BUY_AMOUNT,
|
||||
encodeCurveData(),
|
||||
);
|
||||
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
|
||||
});
|
||||
|
||||
it('reverts if ERC20->ETH receives an ETH input token', async () => {
|
||||
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
|
||||
const call = lp.sellTokenForEth(ETH_TOKEN_ADDRESS, RECIPIENT, BUY_AMOUNT, encodeCurveData());
|
||||
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
|
||||
});
|
||||
|
||||
it('reverts if ETH->ERC20 receives an ETH output token', async () => {
|
||||
await fundProviderContractAsync(ETH_COIN_IDX);
|
||||
const call = lp.sellEthForToken(ETH_TOKEN_ADDRESS, RECIPIENT, BUY_AMOUNT, encodeCurveData());
|
||||
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
|
||||
});
|
||||
});
|
@@ -0,0 +1,127 @@
|
||||
import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils';
|
||||
import { encodePositiveSlippageFeeTransformerData } from '@0x/protocol-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import {
|
||||
PositiveSlippageFeeTransformerContract,
|
||||
TestMintableERC20TokenContract,
|
||||
TestTransformerHostContract,
|
||||
} from '../wrappers';
|
||||
|
||||
const { ZERO_AMOUNT } = constants;
|
||||
|
||||
blockchainTests.resets('PositiveSlippageFeeTransformer', env => {
|
||||
const recipient = randomAddress();
|
||||
let caller: string;
|
||||
let token: TestMintableERC20TokenContract;
|
||||
let transformer: PositiveSlippageFeeTransformerContract;
|
||||
let host: TestTransformerHostContract;
|
||||
|
||||
before(async () => {
|
||||
[caller] = await env.getAccountAddressesAsync();
|
||||
token = await TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestMintableERC20Token,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
transformer = await PositiveSlippageFeeTransformerContract.deployFrom0xArtifactAsync(
|
||||
artifacts.PositiveSlippageFeeTransformer,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
host = await TestTransformerHostContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestTransformerHost,
|
||||
env.provider,
|
||||
{ ...env.txDefaults, from: caller },
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
interface Balances {
|
||||
ethBalance: BigNumber;
|
||||
tokenBalance: BigNumber;
|
||||
}
|
||||
|
||||
async function getBalancesAsync(owner: string): Promise<Balances> {
|
||||
return {
|
||||
ethBalance: await env.web3Wrapper.getBalanceInWeiAsync(owner),
|
||||
tokenBalance: await token.balanceOf(owner).callAsync(),
|
||||
};
|
||||
}
|
||||
|
||||
async function mintHostTokensAsync(amount: BigNumber): Promise<void> {
|
||||
await token.mint(host.address, amount).awaitTransactionSuccessAsync();
|
||||
}
|
||||
|
||||
it('does not transfer positive slippage fees when bestCaseAmount is equal to amount', async () => {
|
||||
const amount = getRandomInteger(1, '1e18');
|
||||
const data = encodePositiveSlippageFeeTransformerData({
|
||||
token: token.address,
|
||||
bestCaseAmount: amount,
|
||||
recipient,
|
||||
});
|
||||
await mintHostTokensAsync(amount);
|
||||
const beforeBalanceHost = await getBalancesAsync(host.address);
|
||||
const beforeBalanceRecipient = await getBalancesAsync(recipient);
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
sender: randomAddress(),
|
||||
taker: randomAddress(),
|
||||
})
|
||||
.awaitTransactionSuccessAsync();
|
||||
expect(await getBalancesAsync(host.address)).to.deep.eq(beforeBalanceHost);
|
||||
expect(await getBalancesAsync(recipient)).to.deep.eq(beforeBalanceRecipient);
|
||||
});
|
||||
|
||||
it('does not transfer positive slippage fees when bestCaseAmount is higher than amount', async () => {
|
||||
const amount = getRandomInteger(1, '1e18');
|
||||
const bestCaseAmount = amount.times(1.1).decimalPlaces(0, BigNumber.ROUND_FLOOR);
|
||||
const data = encodePositiveSlippageFeeTransformerData({
|
||||
token: token.address,
|
||||
bestCaseAmount,
|
||||
recipient,
|
||||
});
|
||||
await mintHostTokensAsync(amount);
|
||||
const beforeBalanceHost = await getBalancesAsync(host.address);
|
||||
const beforeBalanceRecipient = await getBalancesAsync(recipient);
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
sender: randomAddress(),
|
||||
taker: randomAddress(),
|
||||
})
|
||||
.awaitTransactionSuccessAsync();
|
||||
expect(await getBalancesAsync(host.address)).to.deep.eq(beforeBalanceHost);
|
||||
expect(await getBalancesAsync(recipient)).to.deep.eq(beforeBalanceRecipient);
|
||||
});
|
||||
|
||||
it('send positive slippage fee to recipient when bestCaseAmount is lower than amount', async () => {
|
||||
const amount = getRandomInteger(1, '1e18');
|
||||
const bestCaseAmount = amount.times(0.95).decimalPlaces(0, BigNumber.ROUND_FLOOR);
|
||||
const data = encodePositiveSlippageFeeTransformerData({
|
||||
token: token.address,
|
||||
bestCaseAmount,
|
||||
recipient,
|
||||
});
|
||||
await mintHostTokensAsync(amount);
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
sender: randomAddress(),
|
||||
taker: randomAddress(),
|
||||
})
|
||||
.awaitTransactionSuccessAsync();
|
||||
expect(await getBalancesAsync(host.address)).to.deep.eq({
|
||||
tokenBalance: bestCaseAmount,
|
||||
ethBalance: ZERO_AMOUNT,
|
||||
});
|
||||
expect(await getBalancesAsync(recipient)).to.deep.eq({
|
||||
tokenBalance: amount.minus(bestCaseAmount), // positive slippage
|
||||
ethBalance: ZERO_AMOUNT,
|
||||
});
|
||||
});
|
||||
});
|
@@ -8,6 +8,7 @@ export * from '../test/generated-wrappers/allowance_target';
|
||||
export * from '../test/generated-wrappers/bootstrap_feature';
|
||||
export * from '../test/generated-wrappers/bridge_adapter';
|
||||
export * from '../test/generated-wrappers/bridge_source';
|
||||
export * from '../test/generated-wrappers/curve_liquidity_provider';
|
||||
export * from '../test/generated-wrappers/fee_collector';
|
||||
export * from '../test/generated-wrappers/fee_collector_controller';
|
||||
export * from '../test/generated-wrappers/fill_quote_transformer';
|
||||
@@ -75,6 +76,7 @@ export * from '../test/generated-wrappers/mixin_co_fi_x';
|
||||
export * from '../test/generated-wrappers/mixin_crypto_com';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
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_m_stable';
|
||||
export * from '../test/generated-wrappers/mixin_mooniswap';
|
||||
@@ -88,9 +90,11 @@ export * from '../test/generated-wrappers/native_orders_feature';
|
||||
export * from '../test/generated-wrappers/ownable_feature';
|
||||
export * from '../test/generated-wrappers/pay_taker_transformer';
|
||||
export * from '../test/generated-wrappers/permissionless_transformer_deployer';
|
||||
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';
|
||||
export * from '../test/generated-wrappers/test_call_target';
|
||||
export * from '../test/generated-wrappers/test_curve';
|
||||
export * from '../test/generated-wrappers/test_delegate_caller';
|
||||
export * from '../test/generated-wrappers/test_fee_collector_controller';
|
||||
export * from '../test/generated-wrappers/test_fill_quote_transformer_bridge';
|
||||
|
@@ -5,6 +5,7 @@
|
||||
"files": [
|
||||
"generated-artifacts/AffiliateFeeTransformer.json",
|
||||
"generated-artifacts/BridgeAdapter.json",
|
||||
"generated-artifacts/CurveLiquidityProvider.json",
|
||||
"generated-artifacts/FeeCollector.json",
|
||||
"generated-artifacts/FeeCollectorController.json",
|
||||
"generated-artifacts/FillQuoteTransformer.json",
|
||||
@@ -26,6 +27,7 @@
|
||||
"generated-artifacts/NativeOrdersFeature.json",
|
||||
"generated-artifacts/OwnableFeature.json",
|
||||
"generated-artifacts/PayTakerTransformer.json",
|
||||
"generated-artifacts/PositiveSlippageFeeTransformer.json",
|
||||
"generated-artifacts/SimpleFunctionRegistryFeature.json",
|
||||
"generated-artifacts/TokenSpenderFeature.json",
|
||||
"generated-artifacts/TransformERC20Feature.json",
|
||||
@@ -36,6 +38,7 @@
|
||||
"test/generated-artifacts/BootstrapFeature.json",
|
||||
"test/generated-artifacts/BridgeAdapter.json",
|
||||
"test/generated-artifacts/BridgeSource.json",
|
||||
"test/generated-artifacts/CurveLiquidityProvider.json",
|
||||
"test/generated-artifacts/FeeCollector.json",
|
||||
"test/generated-artifacts/FeeCollectorController.json",
|
||||
"test/generated-artifacts/FillQuoteTransformer.json",
|
||||
@@ -103,6 +106,7 @@
|
||||
"test/generated-artifacts/MixinCryptoCom.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
"test/generated-artifacts/MixinDodo.json",
|
||||
"test/generated-artifacts/MixinDodoV2.json",
|
||||
"test/generated-artifacts/MixinKyber.json",
|
||||
"test/generated-artifacts/MixinMStable.json",
|
||||
"test/generated-artifacts/MixinMooniswap.json",
|
||||
@@ -116,9 +120,11 @@
|
||||
"test/generated-artifacts/OwnableFeature.json",
|
||||
"test/generated-artifacts/PayTakerTransformer.json",
|
||||
"test/generated-artifacts/PermissionlessTransformerDeployer.json",
|
||||
"test/generated-artifacts/PositiveSlippageFeeTransformer.json",
|
||||
"test/generated-artifacts/SimpleFunctionRegistryFeature.json",
|
||||
"test/generated-artifacts/TestBridge.json",
|
||||
"test/generated-artifacts/TestCallTarget.json",
|
||||
"test/generated-artifacts/TestCurve.json",
|
||||
"test/generated-artifacts/TestDelegateCaller.json",
|
||||
"test/generated-artifacts/TestFeeCollectorController.json",
|
||||
"test/generated-artifacts/TestFillQuoteTransformerBridge.json",
|
||||
|
@@ -1,4 +1,62 @@
|
||||
[
|
||||
{
|
||||
"version": "6.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Filter MultiHop where second source is not present",
|
||||
"pr": 138
|
||||
},
|
||||
{
|
||||
"note": "Add CurveLiquidityProvider \"direct\" route to EP consumer.",
|
||||
"pr": 127
|
||||
},
|
||||
{
|
||||
"note": "Fix compiler error on `ILiquidityProvider` call",
|
||||
"pr": 127
|
||||
},
|
||||
{
|
||||
"note": "Add deployed `CurveLiquidityProvider` addresses",
|
||||
"pr": 144
|
||||
},
|
||||
{
|
||||
"note": "Support `Mirror Protocol` with hops to `UST`",
|
||||
"pr": 142
|
||||
},
|
||||
{
|
||||
"note": "Fix protocol fee in fee schedule for `RfqOrder`",
|
||||
"pr": 146
|
||||
},
|
||||
{
|
||||
"note": "Special case BNB in uni v1 sampler",
|
||||
"pr": 147
|
||||
},
|
||||
{
|
||||
"note": "Create `FakeTaker` contract to get result data and gas used",
|
||||
"pr": 151
|
||||
},
|
||||
{
|
||||
"note": "Added support for `Dodo` v2",
|
||||
"pr": 152
|
||||
},
|
||||
{
|
||||
"note": "Added support for `Linkswap`",
|
||||
"pr": 153
|
||||
},
|
||||
{
|
||||
"note": "Re-add WBTC in default intermediate hops",
|
||||
"pr": 154
|
||||
},
|
||||
{
|
||||
"note": "Add an alternative RFQ market making implementation",
|
||||
"pr": 139
|
||||
},
|
||||
{
|
||||
"note": "Added an opt-in `PositiveSlippageAffiliateFee`",
|
||||
"pr": 101
|
||||
}
|
||||
],
|
||||
"timestamp": 1614141718
|
||||
},
|
||||
{
|
||||
"version": "6.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.1.0 - _February 24, 2021_
|
||||
|
||||
* Filter MultiHop where second source is not present (#138)
|
||||
* Add CurveLiquidityProvider "direct" route to EP consumer. (#127)
|
||||
* Fix compiler error on `ILiquidityProvider` call (#127)
|
||||
* Add deployed `CurveLiquidityProvider` addresses (#144)
|
||||
* Support `Mirror Protocol` with hops to `UST` (#142)
|
||||
* Fix protocol fee in fee schedule for `RfqOrder` (#146)
|
||||
* Special case BNB in uni v1 sampler (#147)
|
||||
* Create `FakeTaker` contract to get result data and gas used (#151)
|
||||
* Added support for `Dodo` v2 (#152)
|
||||
* Added support for `Linkswap` (#153)
|
||||
* Re-add WBTC in default intermediate hops (#154)
|
||||
* Add an alternative RFQ market making implementation (#139)
|
||||
* Added an opt-in `PositiveSlippageAffiliateFee` (#101)
|
||||
|
||||
## v6.0.0 - _February 10, 2021_
|
||||
|
||||
* Pull top 250 Balancer pairs on initialization (#113)
|
||||
|
206
packages/asset-swapper/contracts/src/DODOV2Sampler.sol
Normal file
206
packages/asset-swapper/contracts/src/DODOV2Sampler.sol
Normal file
@@ -0,0 +1,206 @@
|
||||
// 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 "./DeploymentConstants.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
interface IDODOV2Registry {
|
||||
function getDODOPool(address baseToken, address quoteToken)
|
||||
external
|
||||
view
|
||||
returns (address[] memory machines);
|
||||
}
|
||||
|
||||
interface IDODOV2Pool {
|
||||
function querySellBase(address trader, uint256 payBaseAmount)
|
||||
external
|
||||
view
|
||||
returns (uint256 receiveQuoteAmount, uint256 mtFee);
|
||||
|
||||
function querySellQuote(address trader, uint256 payQuoteAmount)
|
||||
external
|
||||
view
|
||||
returns (uint256 receiveBaseAmount, uint256 mtFee);
|
||||
}
|
||||
|
||||
contract DODOV2Sampler is
|
||||
DeploymentConstants,
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
/// @dev Gas limit for DODO V2 calls.
|
||||
uint256 constant private DODO_V2_CALL_GAS = 300e3; // 300k
|
||||
|
||||
/// @dev Sample sell quotes from DODO V2.
|
||||
/// @param registry Address of the registry to look up.
|
||||
/// @param offset offset index for the pool in the registry.
|
||||
/// @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 sellBase whether the bridge needs to sell the base token
|
||||
/// @return pool the DODO pool address
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromDODOV2(
|
||||
address registry,
|
||||
uint256 offset,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
(pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
|
||||
if (pool == address(0)) {
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = _sampleSellForApproximateBuyFromDODOV2(
|
||||
abi.encode(takerToken, pool, sellBase), // taker token data
|
||||
abi.encode(makerToken, pool, sellBase), // maker token data
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
// Exit early if the amount is too high for the source to serve
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from DODO.
|
||||
/// @param registry Address of the registry to look up.
|
||||
/// @param offset offset index for the pool in the registry.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return sellBase whether the bridge needs to sell the base token
|
||||
/// @return pool the DODO pool address
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromDODOV2(
|
||||
address registry,
|
||||
uint256 offset,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
(pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
|
||||
if (pool == address(0)) {
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
}
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, pool, !sellBase),
|
||||
takerTokenData: abi.encode(takerToken, pool, sellBase),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromDODOV2
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromDODOV2(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory /* makerTokenData */,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(address takerToken, address pool, bool sellBase) = abi.decode(
|
||||
takerTokenData,
|
||||
(address, address, bool)
|
||||
);
|
||||
|
||||
// We will get called to sell both the taker token and also to sell the maker token
|
||||
// since we use approximate buy for sell and buy functions
|
||||
if (sellBase) {
|
||||
try
|
||||
IDODOV2Pool(pool).querySellBase
|
||||
{ gas: DODO_V2_CALL_GAS }
|
||||
(address(0), sellAmount)
|
||||
returns (uint256 amount, uint256)
|
||||
{
|
||||
return amount;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
try
|
||||
IDODOV2Pool(pool).querySellQuote
|
||||
{ gas: DODO_V2_CALL_GAS }
|
||||
(address(0), sellAmount)
|
||||
returns (uint256 amount, uint256)
|
||||
{
|
||||
return amount;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _getNextDODOV2Pool(
|
||||
address registry,
|
||||
uint256 offset,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (address machine, bool sellBase)
|
||||
{
|
||||
// Query in base -> quote direction, if a pool is found then we are selling the base
|
||||
address[] memory machines = IDODOV2Registry(registry).getDODOPool(takerToken, makerToken);
|
||||
sellBase = true;
|
||||
if (machines.length == 0) {
|
||||
// Query in quote -> base direction, if a pool is found then we are selling the quote
|
||||
machines = IDODOV2Registry(registry).getDODOPool(makerToken, takerToken);
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
if (offset >= machines.length) {
|
||||
return (address(0), false);
|
||||
}
|
||||
|
||||
machine = machines[offset];
|
||||
}
|
||||
|
||||
}
|
@@ -24,6 +24,7 @@ import "./BalancerSampler.sol";
|
||||
import "./BancorSampler.sol";
|
||||
import "./CurveSampler.sol";
|
||||
import "./DODOSampler.sol";
|
||||
import "./DODOV2Sampler.sol";
|
||||
import "./Eth2DaiSampler.sol";
|
||||
import "./KyberSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
@@ -44,6 +45,7 @@ contract ERC20BridgeSampler is
|
||||
BancorSampler,
|
||||
CurveSampler,
|
||||
DODOSampler,
|
||||
DODOV2Sampler,
|
||||
Eth2DaiSampler,
|
||||
KyberSampler,
|
||||
LiquidityProviderSampler,
|
||||
|
27
packages/asset-swapper/contracts/src/FakeTaker.sol
Normal file
27
packages/asset-swapper/contracts/src/FakeTaker.sol
Normal file
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract FakeTaker {
|
||||
|
||||
struct Result {
|
||||
bool success;
|
||||
bytes resultData;
|
||||
uint256 gasUsed;
|
||||
}
|
||||
|
||||
receive() payable external {}
|
||||
|
||||
function execute(address payable to, bytes calldata data)
|
||||
public
|
||||
payable
|
||||
returns (Result memory result)
|
||||
{
|
||||
uint256 gasBefore = gasleft();
|
||||
(
|
||||
result.success,
|
||||
result.resultData
|
||||
) = to.call{ value: msg.value }(data);
|
||||
result.gasUsed = gasBefore - gasleft();
|
||||
}
|
||||
}
|
@@ -58,7 +58,11 @@ contract LiquidityProviderSampler is
|
||||
try
|
||||
ILiquidityProvider(providerAddress).getSellQuote
|
||||
{gas: DEFAULT_CALL_GAS}
|
||||
(takerToken, makerToken, takerTokenAmounts[i])
|
||||
(
|
||||
IERC20TokenV06(takerToken),
|
||||
IERC20TokenV06(makerToken),
|
||||
takerTokenAmounts[i]
|
||||
)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
|
@@ -42,6 +42,8 @@ contract UniswapSampler is
|
||||
{
|
||||
/// @dev Gas limit for Uniswap calls.
|
||||
uint256 constant private UNISWAP_CALL_GAS = 150e3; // 150k
|
||||
// @dev The BNB token is poisoned on uniswap v1.
|
||||
address constant private BAD_MAKER_TOKEN = 0xB8c77482e45F1F44dE1745F52C74426C631bDD52;
|
||||
|
||||
/// @dev Sample sell quotes from Uniswap.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
@@ -61,6 +63,10 @@ contract UniswapSampler is
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
if (makerToken == BAD_MAKER_TOKEN) {
|
||||
// BNB is poisoned on v1. You can only sell to it.
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
@@ -120,6 +126,10 @@ contract UniswapSampler is
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
if (makerToken == BAD_MAKER_TOKEN) {
|
||||
// BNB is poisoned on v1. You can only sell to it.
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
|
@@ -45,7 +45,7 @@ contract TestNativeOrderSampler is
|
||||
UtilitySampler
|
||||
{
|
||||
uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1;
|
||||
bytes32 private constant VALID_SIGNATURE_HASH = keccak256(hex"01");
|
||||
bytes32 private constant VALID_SIGNATURE_HASH = bytes32(hex"01");
|
||||
|
||||
function createTokens(uint256 count)
|
||||
external
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/asset-swapper",
|
||||
"version": "6.0.0",
|
||||
"version": "6.1.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -36,9 +36,9 @@
|
||||
"publish:private": "yarn build && gitpkg publish"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker",
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json",
|
||||
"postpublish": {
|
||||
"assets": []
|
||||
}
|
||||
@@ -59,11 +59,11 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.21",
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contract-addresses": "^5.10.0",
|
||||
"@0x/contract-wrappers": "^13.12.3",
|
||||
"@0x/contract-addresses": "^5.11.0",
|
||||
"@0x/contract-wrappers": "^13.13.0",
|
||||
"@0x/dev-utils": "^4.2.1",
|
||||
"@0x/json-schemas": "^5.4.1",
|
||||
"@0x/protocol-utils": "^1.2.0",
|
||||
"@0x/protocol-utils": "^1.3.0",
|
||||
"@0x/quote-server": "^4.0.1",
|
||||
"@0x/types": "^3.3.1",
|
||||
"@0x/typescript-typings": "^5.1.6",
|
||||
@@ -86,16 +86,16 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0x/base-contract": "^6.2.18",
|
||||
"@0x/contracts-asset-proxy": "^3.7.6",
|
||||
"@0x/contracts-erc20": "^3.3.3",
|
||||
"@0x/contracts-exchange": "^3.2.25",
|
||||
"@0x/contracts-exchange-libs": "^4.3.24",
|
||||
"@0x/contracts-asset-proxy": "^3.7.7",
|
||||
"@0x/contracts-erc20": "^3.3.4",
|
||||
"@0x/contracts-exchange": "^3.2.26",
|
||||
"@0x/contracts-exchange-libs": "^4.3.25",
|
||||
"@0x/contracts-gen": "^2.0.30",
|
||||
"@0x/contracts-test-utils": "^5.3.21",
|
||||
"@0x/contracts-utils": "^4.7.3",
|
||||
"@0x/contracts-zero-ex": "^0.18.2",
|
||||
"@0x/contracts-test-utils": "^5.3.22",
|
||||
"@0x/contracts-utils": "^4.7.4",
|
||||
"@0x/contracts-zero-ex": "^0.19.0",
|
||||
"@0x/mesh-rpc-client": "^9.4.2",
|
||||
"@0x/migrations": "^6.6.0",
|
||||
"@0x/migrations": "^7.0.0",
|
||||
"@0x/sol-compiler": "^4.5.2",
|
||||
"@0x/subproviders": "^6.4.1",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -7,7 +7,9 @@ import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as BalanceChecker from '../generated-artifacts/BalanceChecker.json';
|
||||
import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json';
|
||||
import * as FakeTaker from '../generated-artifacts/FakeTaker.json';
|
||||
export const artifacts = {
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
BalanceChecker: BalanceChecker as ContractArtifact,
|
||||
FakeTaker: FakeTaker as ContractArtifact,
|
||||
};
|
||||
|
@@ -3,6 +3,7 @@ import { SignatureType } from '@0x/protocol-utils';
|
||||
import { BigNumber, logUtils } from '@0x/utils';
|
||||
|
||||
import {
|
||||
AffiliateFeeType,
|
||||
ExchangeProxyContractOpts,
|
||||
LogFunction,
|
||||
OrderPrunerOpts,
|
||||
@@ -12,7 +13,11 @@ import {
|
||||
SwapQuoteRequestOpts,
|
||||
SwapQuoterOpts,
|
||||
} from './types';
|
||||
import { DEFAULT_GET_MARKET_ORDERS_OPTS, TOKENS } from './utils/market_operation_utils/constants';
|
||||
import {
|
||||
DEFAULT_GET_MARKET_ORDERS_OPTS,
|
||||
DEFAULT_INTERMEDIATE_TOKENS,
|
||||
DEFAULT_TOKEN_ADJACENCY_GRAPH,
|
||||
} from './utils/market_operation_utils/constants';
|
||||
|
||||
const ETH_GAS_STATION_API_URL = 'https://ethgasstation.info/api/ethgasAPI.json';
|
||||
const NULL_BYTES = '0x';
|
||||
@@ -24,6 +29,7 @@ const ONE_MINUTE_SECS = 60;
|
||||
const ONE_MINUTE_MS = ONE_SECOND_MS * ONE_MINUTE_SECS;
|
||||
const DEFAULT_PER_PAGE = 1000;
|
||||
const ZERO_AMOUNT = new BigNumber(0);
|
||||
const ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS = 180;
|
||||
|
||||
const DEFAULT_ORDER_PRUNER_OPTS: OrderPrunerOpts = {
|
||||
expiryBufferMs: 120000, // 2 minutes
|
||||
@@ -37,23 +43,24 @@ const PROTOCOL_FEE_MULTIPLIER = new BigNumber(70000);
|
||||
// default 50% buffer for selecting native orders to be aggregated with other sources
|
||||
const MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE = 0.5;
|
||||
|
||||
const DEFAULT_INTERMEDIATE_TOKENS = [TOKENS.WETH, TOKENS.USDT, TOKENS.DAI, TOKENS.USDC];
|
||||
const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
|
||||
chainId: ChainId.Mainnet,
|
||||
orderRefreshIntervalMs: 10000, // 10 seconds
|
||||
...DEFAULT_ORDER_PRUNER_OPTS,
|
||||
samplerGasLimit: 250e6,
|
||||
samplerGasLimit: 500e6,
|
||||
ethGasStationUrl: ETH_GAS_STATION_API_URL,
|
||||
rfqt: {
|
||||
takerApiKeyWhitelist: [],
|
||||
makerAssetOfferings: {},
|
||||
},
|
||||
tokenAdjacencyGraph: DEFAULT_TOKEN_ADJACENCY_GRAPH,
|
||||
};
|
||||
|
||||
const DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS: ExchangeProxyContractOpts = {
|
||||
isFromETH: false,
|
||||
isToETH: false,
|
||||
affiliateFee: {
|
||||
feeType: AffiliateFeeType.None,
|
||||
recipient: NULL_ADDRESS,
|
||||
buyTokenFeeAmount: ZERO_AMOUNT,
|
||||
sellTokenFeeAmount: ZERO_AMOUNT,
|
||||
@@ -83,15 +90,14 @@ export const DEFAULT_WARNING_LOGGER: LogFunction = (obj, msg) =>
|
||||
const EMPTY_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
||||
export const INVALID_SIGNATURE = { signatureType: SignatureType.Invalid, v: 1, r: EMPTY_BYTES32, s: EMPTY_BYTES32 };
|
||||
|
||||
export {
|
||||
BRIDGE_ADDRESSES_BY_CHAIN,
|
||||
DEFAULT_FEE_SCHEDULE,
|
||||
DEFAULT_GAS_SCHEDULE,
|
||||
} from './utils/market_operation_utils/constants';
|
||||
export { DEFAULT_FEE_SCHEDULE, DEFAULT_GAS_SCHEDULE } from './utils/market_operation_utils/constants';
|
||||
|
||||
export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(30000);
|
||||
|
||||
export const constants = {
|
||||
ETH_GAS_STATION_API_URL,
|
||||
PROTOCOL_FEE_MULTIPLIER,
|
||||
POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS,
|
||||
NULL_BYTES,
|
||||
ZERO_AMOUNT,
|
||||
NULL_ADDRESS,
|
||||
@@ -115,4 +121,5 @@ export const constants = {
|
||||
DEFAULT_INFO_LOGGER,
|
||||
DEFAULT_WARNING_LOGGER,
|
||||
EMPTY_BYTES32,
|
||||
ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS,
|
||||
};
|
||||
|
@@ -74,7 +74,10 @@ export { InsufficientAssetLiquidityError } from './errors';
|
||||
export { SwapQuoteConsumer } from './quote_consumers/swap_quote_consumer';
|
||||
export { SwapQuoter, Orderbook } from './swap_quoter';
|
||||
export {
|
||||
AffiliateFee,
|
||||
AltOffering,
|
||||
AltRfqtMakerAssetOfferings,
|
||||
AffiliateFeeType,
|
||||
AffiliateFeeAmount,
|
||||
AssetSwapperContractAddresses,
|
||||
CalldataInfo,
|
||||
ExchangeProxyContractOpts,
|
||||
@@ -107,7 +110,7 @@ export {
|
||||
} from './types';
|
||||
export { affiliateFeeUtils } from './utils/affiliate_fee_utils';
|
||||
export {
|
||||
BRIDGE_ADDRESSES_BY_CHAIN,
|
||||
DEFAULT_TOKEN_ADJACENCY_GRAPH,
|
||||
DEFAULT_GAS_SCHEDULE,
|
||||
SOURCE_FLAGS,
|
||||
} from './utils/market_operation_utils/constants';
|
||||
@@ -162,7 +165,7 @@ export {
|
||||
QuoteReportEntry,
|
||||
} from './utils/quote_report_generator';
|
||||
export { QuoteRequestor } from './utils/quote_requestor';
|
||||
export { ERC20BridgeSamplerContract, BalanceCheckerContract } from './wrappers';
|
||||
export { ERC20BridgeSamplerContract, BalanceCheckerContract, FakeTakerContract } from './wrappers';
|
||||
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
|
||||
export type Native = ERC20BridgeSource.Native;
|
||||
export type MultiHop = ERC20BridgeSource.MultiHop;
|
||||
|
@@ -2,8 +2,10 @@ import { ContractAddresses } from '@0x/contract-addresses';
|
||||
import { IZeroExContract } from '@0x/contract-wrappers';
|
||||
import {
|
||||
encodeAffiliateFeeTransformerData,
|
||||
encodeCurveLiquidityProviderData,
|
||||
encodeFillQuoteTransformerData,
|
||||
encodePayTakerTransformerData,
|
||||
encodePositiveSlippageFeeTransformerData,
|
||||
encodeWethTransformerData,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
FillQuoteTransformerData,
|
||||
@@ -15,8 +17,9 @@ import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import { SupportedProvider, ZeroExProvider } from '@0x/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from '../constants';
|
||||
import { constants, POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS } from '../constants';
|
||||
import {
|
||||
AffiliateFeeType,
|
||||
CalldataInfo,
|
||||
ExchangeProxyContractOpts,
|
||||
MarketBuySwapQuote,
|
||||
@@ -29,11 +32,13 @@ import {
|
||||
SwapQuoteGetOutputOpts,
|
||||
} from '../types';
|
||||
import { assert } from '../utils/assert';
|
||||
import { CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID } from '../utils/market_operation_utils/constants';
|
||||
import {
|
||||
createBridgeDataForBridgeOrder,
|
||||
getERC20BridgeSourceToBridgeSource,
|
||||
} from '../utils/market_operation_utils/orders';
|
||||
import {
|
||||
CurveFillData,
|
||||
ERC20BridgeSource,
|
||||
LiquidityProviderFillData,
|
||||
NativeLimitOrderFillData,
|
||||
@@ -56,6 +61,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
payTakerTransformer: number;
|
||||
fillQuoteTransformer: number;
|
||||
affiliateFeeTransformer: number;
|
||||
positiveSlippageFeeTransformer: number;
|
||||
};
|
||||
|
||||
private readonly _exchangeProxy: IZeroExContract;
|
||||
@@ -89,6 +95,10 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
contractAddresses.transformers.affiliateFeeTransformer,
|
||||
contractAddresses.exchangeProxyTransformerDeployer,
|
||||
),
|
||||
positiveSlippageFeeTransformer: findTransformerNonce(
|
||||
contractAddresses.transformers.positiveSlippageFeeTransformer,
|
||||
contractAddresses.exchangeProxyTransformerDeployer,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -114,7 +124,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
if (isFromETH) {
|
||||
ethAmount = ethAmount.plus(sellAmount);
|
||||
}
|
||||
const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
|
||||
|
||||
// VIP routes.
|
||||
if (
|
||||
@@ -141,7 +150,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
.getABIEncodedTransactionData(),
|
||||
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
|
||||
toAddress: this._exchangeProxy.address,
|
||||
allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget,
|
||||
allowanceTarget: this._exchangeProxy.address,
|
||||
gasOverhead: ZERO_AMOUNT,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -162,7 +172,34 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
.getABIEncodedTransactionData(),
|
||||
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
|
||||
toAddress: this._exchangeProxy.address,
|
||||
allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget,
|
||||
allowanceTarget: this._exchangeProxy.address,
|
||||
gasOverhead: ZERO_AMOUNT,
|
||||
};
|
||||
}
|
||||
|
||||
if (isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.Curve, ERC20BridgeSource.Swerve])) {
|
||||
const fillData = quote.orders[0].fills[0].fillData as CurveFillData;
|
||||
return {
|
||||
calldataHexString: this._exchangeProxy
|
||||
.sellToLiquidityProvider(
|
||||
isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
|
||||
isToETH ? ETH_TOKEN_ADDRESS : buyToken,
|
||||
CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID[this.chainId],
|
||||
NULL_ADDRESS,
|
||||
sellAmount,
|
||||
minBuyAmount,
|
||||
encodeCurveLiquidityProviderData({
|
||||
curveAddress: fillData.pool.poolAddress,
|
||||
exchangeFunctionSelector: fillData.pool.exchangeFunctionSelector,
|
||||
fromCoinIdx: new BigNumber(fillData.fromTokenIdx),
|
||||
toCoinIdx: new BigNumber(fillData.toTokenIdx),
|
||||
}),
|
||||
)
|
||||
.getABIEncodedTransactionData(),
|
||||
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
|
||||
toAddress: this._exchangeProxy.address,
|
||||
allowanceTarget: this._exchangeProxy.address,
|
||||
gasOverhead: ZERO_AMOUNT,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -234,25 +271,52 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
});
|
||||
}
|
||||
|
||||
// This transformer pays affiliate fees.
|
||||
if (buyTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
||||
const { feeType, buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
|
||||
let gasOverhead = ZERO_AMOUNT;
|
||||
if (feeType === AffiliateFeeType.PositiveSlippageFee && feeRecipient !== NULL_ADDRESS) {
|
||||
// bestCaseAmountWithSurplus is used to cover gas cost of sending positive slipapge fee to fee recipient
|
||||
// this helps avoid sending dust amounts which are not worth the gas cost to transfer
|
||||
let bestCaseAmountWithSurplus = quote.bestCaseQuoteInfo.makerAmount
|
||||
.plus(
|
||||
POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS.multipliedBy(quote.gasPrice).multipliedBy(
|
||||
quote.makerAmountPerEth,
|
||||
),
|
||||
)
|
||||
.integerValue();
|
||||
// In the event makerAmountPerEth is unknown, we only allow for positive slippage which is greater than
|
||||
// the best case amount
|
||||
bestCaseAmountWithSurplus = BigNumber.max(bestCaseAmountWithSurplus, quote.bestCaseQuoteInfo.makerAmount);
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.affiliateFeeTransformer,
|
||||
data: encodeAffiliateFeeTransformerData({
|
||||
fees: [
|
||||
{
|
||||
token: isToETH ? ETH_TOKEN_ADDRESS : buyToken,
|
||||
amount: buyTokenFeeAmount,
|
||||
recipient: feeRecipient,
|
||||
},
|
||||
],
|
||||
deploymentNonce: this.transformerNonces.positiveSlippageFeeTransformer,
|
||||
data: encodePositiveSlippageFeeTransformerData({
|
||||
token: isToETH ? ETH_TOKEN_ADDRESS : buyToken,
|
||||
bestCaseAmount: BigNumber.max(bestCaseAmountWithSurplus, quote.bestCaseQuoteInfo.makerAmount),
|
||||
recipient: feeRecipient,
|
||||
}),
|
||||
});
|
||||
// Adjust the minimum buy amount by the fee.
|
||||
minBuyAmount = BigNumber.max(0, minBuyAmount.minus(buyTokenFeeAmount));
|
||||
}
|
||||
if (sellTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
||||
throw new Error('Affiliate fees denominated in sell token are not yet supported');
|
||||
// This may not be visible at eth_estimateGas time, so we explicitly add overhead
|
||||
gasOverhead = POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS;
|
||||
} else if (feeType === AffiliateFeeType.PercentageFee && feeRecipient !== NULL_ADDRESS) {
|
||||
// This transformer pays affiliate fees.
|
||||
if (buyTokenFeeAmount.isGreaterThan(0)) {
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.affiliateFeeTransformer,
|
||||
data: encodeAffiliateFeeTransformerData({
|
||||
fees: [
|
||||
{
|
||||
token: isToETH ? ETH_TOKEN_ADDRESS : buyToken,
|
||||
amount: buyTokenFeeAmount,
|
||||
recipient: feeRecipient,
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
// Adjust the minimum buy amount by the fee.
|
||||
minBuyAmount = BigNumber.max(0, minBuyAmount.minus(buyTokenFeeAmount));
|
||||
}
|
||||
if (sellTokenFeeAmount.isGreaterThan(0)) {
|
||||
throw new Error('Affiliate fees denominated in sell token are not yet supported');
|
||||
}
|
||||
}
|
||||
|
||||
// The final transformer will send all funds to the taker.
|
||||
@@ -278,7 +342,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
calldataHexString,
|
||||
ethAmount,
|
||||
toAddress: this._exchangeProxy.address,
|
||||
allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget,
|
||||
allowanceTarget: this._exchangeProxy.address,
|
||||
gasOverhead,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -304,6 +369,10 @@ function isDirectSwapCompatible(
|
||||
if (!opts.affiliateFee.buyTokenFeeAmount.eq(0) || !opts.affiliateFee.sellTokenFeeAmount.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
// Must not have a positive slippage fee.
|
||||
if (opts.affiliateFee.feeType === AffiliateFeeType.PositiveSlippageFee) {
|
||||
return false;
|
||||
}
|
||||
// Must be a single order.
|
||||
if (quote.orders.length !== 1) {
|
||||
return false;
|
||||
|
@@ -5,7 +5,7 @@ import { BlockParamLiteral, SupportedProvider, ZeroExProvider } from 'ethereum-t
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { BRIDGE_ADDRESSES_BY_CHAIN, constants, INVALID_SIGNATURE } from './constants';
|
||||
import { constants, INVALID_SIGNATURE } from './constants';
|
||||
import {
|
||||
AssetSwapperContractAddresses,
|
||||
MarketBuySwapQuote,
|
||||
@@ -102,7 +102,6 @@ export class SwapQuoter {
|
||||
this._rfqtOptions = rfqt;
|
||||
this._contractAddresses = options.contractAddresses || {
|
||||
...getContractAddressesForChainOrThrow(chainId),
|
||||
...BRIDGE_ADDRESSES_BY_CHAIN[chainId],
|
||||
};
|
||||
this._protocolFeeUtils = ProtocolFeeUtils.getInstance(
|
||||
constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
|
||||
@@ -349,6 +348,7 @@ export class SwapQuoter {
|
||||
if (calcOpts.rfqt !== undefined) {
|
||||
calcOpts.rfqt.quoteRequestor = new QuoteRequestor(
|
||||
rfqtOptions ? rfqtOptions.makerAssetOfferings || {} : {},
|
||||
rfqtOptions ? rfqtOptions.altRfqCreds : undefined,
|
||||
rfqtOptions ? rfqtOptions.warningLogger : undefined,
|
||||
rfqtOptions ? rfqtOptions.infoLogger : undefined,
|
||||
this.expiryBufferMs,
|
||||
@@ -454,7 +454,7 @@ function createSwapQuote(
|
||||
gasSchedule: FeeSchedule,
|
||||
slippage: number,
|
||||
): SwapQuote {
|
||||
const { optimizedOrders, quoteReport, sourceFlags, takerTokenToEthRate, makerTokenToEthRate } = optimizerResult;
|
||||
const { optimizedOrders, quoteReport, sourceFlags, takerAmountPerEth, makerAmountPerEth } = optimizerResult;
|
||||
const isTwoHop = sourceFlags === SOURCE_FLAGS[ERC20BridgeSource.MultiHop];
|
||||
|
||||
// Calculate quote info
|
||||
@@ -474,8 +474,8 @@ function createSwapQuote(
|
||||
sourceBreakdown,
|
||||
makerTokenDecimals,
|
||||
takerTokenDecimals,
|
||||
takerTokenToEthRate,
|
||||
makerTokenToEthRate,
|
||||
takerAmountPerEth,
|
||||
makerAmountPerEth,
|
||||
quoteReport,
|
||||
isTwoHop,
|
||||
};
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
RfqOrderFields,
|
||||
Signature,
|
||||
} from '@0x/protocol-utils';
|
||||
import { TakerRequestQueryParams } from '@0x/quote-server';
|
||||
import { TakerRequestQueryParams, V4SignedRfqOrder } from '@0x/quote-server';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import {
|
||||
@@ -54,12 +54,15 @@ export interface NativeOrderFillableAmountFields {
|
||||
* toAddress: The contract address to call.
|
||||
* ethAmount: The eth amount in wei to send with the smart contract call.
|
||||
* allowanceTarget: The address the taker should grant an allowance to.
|
||||
* gasOverhead: The gas overhead needed to be added to the gas limit to allow for optional
|
||||
* operations which may not visible at eth_estimateGas time
|
||||
*/
|
||||
export interface CalldataInfo {
|
||||
calldataHexString: string;
|
||||
toAddress: string;
|
||||
ethAmount: BigNumber;
|
||||
allowanceTarget: string;
|
||||
gasOverhead: BigNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +101,14 @@ export interface SwapQuoteExecutionOpts extends SwapQuoteGetOutputOpts {
|
||||
gasLimit?: number;
|
||||
}
|
||||
|
||||
export interface AffiliateFee {
|
||||
export enum AffiliateFeeType {
|
||||
None,
|
||||
PercentageFee,
|
||||
PositiveSlippageFee,
|
||||
}
|
||||
|
||||
export interface AffiliateFeeAmount {
|
||||
feeType: AffiliateFeeType;
|
||||
recipient: string;
|
||||
buyTokenFeeAmount: BigNumber;
|
||||
sellTokenFeeAmount: BigNumber;
|
||||
@@ -130,7 +140,7 @@ export enum ExchangeProxyRefundReceiver {
|
||||
export interface ExchangeProxyContractOpts {
|
||||
isFromETH: boolean;
|
||||
isToETH: boolean;
|
||||
affiliateFee: AffiliateFee;
|
||||
affiliateFee: AffiliateFeeAmount;
|
||||
refundReceiver: string | ExchangeProxyRefundReceiver;
|
||||
isMetaTransaction: boolean;
|
||||
shouldSellEntireBalance: boolean;
|
||||
@@ -161,8 +171,8 @@ export interface SwapQuoteBase {
|
||||
isTwoHop: boolean;
|
||||
makerTokenDecimals: number;
|
||||
takerTokenDecimals: number;
|
||||
takerTokenToEthRate: BigNumber;
|
||||
makerTokenToEthRate: BigNumber;
|
||||
takerAmountPerEth: BigNumber;
|
||||
makerAmountPerEth: BigNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +238,7 @@ export interface RfqtRequestOpts {
|
||||
isIndicative?: boolean;
|
||||
makerEndpointMaxResponseTimeMs?: number;
|
||||
nativeExclusivelyRFQT?: boolean;
|
||||
altRfqtAssetOfferings?: AltRfqtMakerAssetOfferings;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,6 +257,25 @@ export interface RfqtMakerAssetOfferings {
|
||||
[endpoint: string]: Array<[string, string]>;
|
||||
}
|
||||
|
||||
export interface AltOffering {
|
||||
id: string;
|
||||
baseAsset: string;
|
||||
quoteAsset: string;
|
||||
baseAssetDecimals: number;
|
||||
quoteAssetDecimals: number;
|
||||
}
|
||||
export interface AltRfqtMakerAssetOfferings {
|
||||
[endpoint: string]: AltOffering[];
|
||||
}
|
||||
export enum RfqPairType {
|
||||
Standard = 'standard',
|
||||
Alt = 'alt',
|
||||
}
|
||||
export interface TypedMakerUrl {
|
||||
url: string;
|
||||
pairType: RfqPairType;
|
||||
}
|
||||
|
||||
export type LogFunction = (obj: object, msg?: string, ...args: any[]) => void;
|
||||
|
||||
export interface RfqtFirmQuoteValidator {
|
||||
@@ -255,11 +285,15 @@ export interface RfqtFirmQuoteValidator {
|
||||
export interface SwapQuoterRfqtOpts {
|
||||
takerApiKeyWhitelist: string[];
|
||||
makerAssetOfferings: RfqtMakerAssetOfferings;
|
||||
altRfqCreds?: {
|
||||
altRfqApiKey: string;
|
||||
altRfqProfile: string;
|
||||
};
|
||||
warningLogger?: LogFunction;
|
||||
infoLogger?: LogFunction;
|
||||
}
|
||||
|
||||
export type AssetSwapperContractAddresses = ContractAddresses & BridgeContractAddresses;
|
||||
export type AssetSwapperContractAddresses = ContractAddresses;
|
||||
|
||||
/**
|
||||
* chainId: The ethereum chain id. Defaults to 1 (mainnet).
|
||||
@@ -333,6 +367,17 @@ export interface MockedRfqtQuoteResponse {
|
||||
responseCode: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a mocked RFQT maker responses.
|
||||
*/
|
||||
export interface AltMockedRfqtQuoteResponse {
|
||||
endpoint: string;
|
||||
mmApiKey: string;
|
||||
requestData: AltQuoteRequestData;
|
||||
responseData: any;
|
||||
responseCode: number;
|
||||
}
|
||||
|
||||
export interface SamplerOverrides {
|
||||
overrides: GethCallOverrides;
|
||||
block: BlockParam;
|
||||
@@ -344,25 +389,50 @@ export interface SamplerCallResult {
|
||||
}
|
||||
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
/**
|
||||
* The Contract addresses of the deployed Bridges
|
||||
*/
|
||||
export interface BridgeContractAddresses {
|
||||
uniswapBridge: string;
|
||||
uniswapV2Bridge: string;
|
||||
eth2DaiBridge: string;
|
||||
kyberBridge: string;
|
||||
curveBridge: string;
|
||||
multiBridge: string;
|
||||
balancerBridge: string;
|
||||
bancorBridge: string;
|
||||
mStableBridge: string;
|
||||
mooniswapBridge: string;
|
||||
sushiswapBridge: string;
|
||||
shellBridge: string;
|
||||
dodoBridge: string;
|
||||
creamBridge: string;
|
||||
swerveBridge: string;
|
||||
snowswapBridge: string;
|
||||
cryptoComBridge: string;
|
||||
|
||||
export enum AltQuoteModel {
|
||||
Firm = 'firm',
|
||||
Indicative = 'indicative',
|
||||
}
|
||||
|
||||
export enum AltQuoteSide {
|
||||
Buy = 'buy',
|
||||
Sell = 'sell',
|
||||
}
|
||||
|
||||
export interface AltQuoteRequestData {
|
||||
market: string;
|
||||
model: AltQuoteModel;
|
||||
profile: string;
|
||||
side: AltQuoteSide;
|
||||
value?: string;
|
||||
amount?: string;
|
||||
meta: {
|
||||
txOrigin: string;
|
||||
taker: string;
|
||||
client: string;
|
||||
existingOrder?: {
|
||||
price: string;
|
||||
value?: string;
|
||||
amount?: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface AltBaseRfqResponse extends AltQuoteRequestData {
|
||||
id: string;
|
||||
price?: string;
|
||||
}
|
||||
|
||||
export interface AltIndicativeQuoteResponse extends AltBaseRfqResponse {
|
||||
model: AltQuoteModel.Indicative;
|
||||
status: 'live' | 'rejected';
|
||||
}
|
||||
|
||||
export interface AltFirmQuoteResponse extends AltBaseRfqResponse {
|
||||
model: AltQuoteModel.Firm;
|
||||
data: {
|
||||
'0xv4order': V4SignedRfqOrder;
|
||||
};
|
||||
status: 'active' | 'rejected';
|
||||
}
|
||||
|
233
packages/asset-swapper/src/utils/alt_mm_implementation_utils.ts
Normal file
233
packages/asset-swapper/src/utils/alt_mm_implementation_utils.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
import { Web3Wrapper } from '@0x/dev-utils';
|
||||
import { TakerRequestQueryParams, V4RFQFirmQuote, V4RFQIndicativeQuote } from '@0x/quote-server';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { AxiosInstance } from 'axios';
|
||||
|
||||
import { constants } from '../constants';
|
||||
import {
|
||||
AltFirmQuoteResponse,
|
||||
AltIndicativeQuoteResponse,
|
||||
AltOffering,
|
||||
AltQuoteModel,
|
||||
AltQuoteRequestData,
|
||||
AltQuoteSide,
|
||||
AltRfqtMakerAssetOfferings,
|
||||
} from '../types';
|
||||
|
||||
function getAltMarketInfo(
|
||||
offerings: AltOffering[],
|
||||
buyTokenAddress: string,
|
||||
sellTokenAddress: string,
|
||||
): AltOffering | undefined {
|
||||
for (const offering of offerings) {
|
||||
if (
|
||||
(buyTokenAddress.toLowerCase() === offering.baseAsset.toLowerCase() &&
|
||||
sellTokenAddress.toLowerCase() === offering.quoteAsset.toLowerCase()) ||
|
||||
(sellTokenAddress.toLowerCase() === offering.baseAsset.toLowerCase() &&
|
||||
buyTokenAddress.toLowerCase() === offering.quoteAsset.toLowerCase())
|
||||
) {
|
||||
return offering;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseFirmQuoteResponseFromAltMM(altFirmQuoteReponse: AltFirmQuoteResponse): V4RFQFirmQuote {
|
||||
return {
|
||||
signedOrder: altFirmQuoteReponse.data['0xv4order'],
|
||||
};
|
||||
}
|
||||
|
||||
function parseIndicativeQuoteResponseFromAltMM(
|
||||
altIndicativeQuoteResponse: AltIndicativeQuoteResponse,
|
||||
altPair: AltOffering,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
): V4RFQIndicativeQuote {
|
||||
let makerAmount: BigNumber;
|
||||
let takerAmount: BigNumber;
|
||||
let quoteAmount: BigNumber;
|
||||
let baseAmount: BigNumber;
|
||||
|
||||
if (!altIndicativeQuoteResponse.price) {
|
||||
throw new Error('Price not returned by alt MM');
|
||||
}
|
||||
if (altIndicativeQuoteResponse.amount) {
|
||||
// if amount is specified, amount is the base token amount
|
||||
baseAmount = Web3Wrapper.toBaseUnitAmount(
|
||||
new BigNumber(altIndicativeQuoteResponse.amount),
|
||||
altPair.baseAssetDecimals,
|
||||
);
|
||||
// if amount is specified, use the price (quote/base) to get the quote amount
|
||||
quoteAmount = Web3Wrapper.toBaseUnitAmount(
|
||||
new BigNumber(altIndicativeQuoteResponse.amount)
|
||||
.times(new BigNumber(altIndicativeQuoteResponse.price))
|
||||
.decimalPlaces(altPair.quoteAssetDecimals, BigNumber.ROUND_DOWN),
|
||||
altPair.quoteAssetDecimals,
|
||||
);
|
||||
} else if (altIndicativeQuoteResponse.value) {
|
||||
// if value is specified, value is the quote token amount
|
||||
quoteAmount = Web3Wrapper.toBaseUnitAmount(
|
||||
new BigNumber(altIndicativeQuoteResponse.value),
|
||||
altPair.quoteAssetDecimals,
|
||||
);
|
||||
// if value is specified, use the price (quote/base) to get the base amount
|
||||
baseAmount = Web3Wrapper.toBaseUnitAmount(
|
||||
new BigNumber(altIndicativeQuoteResponse.value)
|
||||
.dividedBy(new BigNumber(altIndicativeQuoteResponse.price))
|
||||
.decimalPlaces(altPair.baseAssetDecimals, BigNumber.ROUND_DOWN),
|
||||
altPair.baseAssetDecimals,
|
||||
);
|
||||
} else {
|
||||
throw new Error('neither amount or value were specified');
|
||||
}
|
||||
if (makerToken.toLowerCase() === altPair.baseAsset.toLowerCase()) {
|
||||
makerAmount = baseAmount;
|
||||
takerAmount = quoteAmount;
|
||||
} else if (makerToken.toLowerCase() === altPair.quoteAsset.toLowerCase()) {
|
||||
makerAmount = quoteAmount;
|
||||
takerAmount = baseAmount;
|
||||
} else {
|
||||
throw new Error(`Base, quote tokens don't align with maker, taker tokens`);
|
||||
}
|
||||
|
||||
return {
|
||||
makerToken,
|
||||
makerAmount,
|
||||
takerToken,
|
||||
takerAmount,
|
||||
// HACK: alt implementation does not return an expiration with indicative quotes
|
||||
// return now + { IMPUTED EXPIRY SECONDS } to have it included after order checks
|
||||
expiry:
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
new BigNumber(Date.now() / 1000)
|
||||
.integerValue(BigNumber.ROUND_DOWN)
|
||||
.plus(constants.ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a standard quote request into an alt quote request
|
||||
* and return the appropriate standard quote response
|
||||
*/
|
||||
export async function returnQuoteFromAltMMAsync<ResponseT>(
|
||||
url: string,
|
||||
apiKey: string,
|
||||
profile: string,
|
||||
integratorKey: string,
|
||||
quoteModel: AltQuoteModel,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
maxResponseTimeMs: number,
|
||||
altRfqtAssetOfferings: AltRfqtMakerAssetOfferings,
|
||||
takerRequestQueryParams: TakerRequestQueryParams,
|
||||
axiosInstance: AxiosInstance,
|
||||
): Promise<{ data: ResponseT; status: number }> {
|
||||
const altPair = getAltMarketInfo(
|
||||
altRfqtAssetOfferings[url],
|
||||
takerRequestQueryParams.buyTokenAddress,
|
||||
takerRequestQueryParams.sellTokenAddress,
|
||||
);
|
||||
|
||||
if (!altPair) {
|
||||
throw new Error(`Alt pair not found`);
|
||||
}
|
||||
const side = altPair.baseAsset === takerRequestQueryParams.buyTokenAddress ? AltQuoteSide.Sell : AltQuoteSide.Buy;
|
||||
|
||||
// comparison price needs to be quote/base
|
||||
// in the standard implementation, it's maker/taker
|
||||
let altComparisonPrice: string | undefined;
|
||||
if (altPair.quoteAsset === makerToken) {
|
||||
altComparisonPrice = takerRequestQueryParams.comparisonPrice
|
||||
? takerRequestQueryParams.comparisonPrice
|
||||
: undefined;
|
||||
} else {
|
||||
altComparisonPrice = takerRequestQueryParams.comparisonPrice
|
||||
? new BigNumber(takerRequestQueryParams.comparisonPrice).pow(-1).toString()
|
||||
: undefined;
|
||||
}
|
||||
|
||||
let data: AltQuoteRequestData;
|
||||
data = {
|
||||
market: `${altPair.id}`,
|
||||
model: quoteModel,
|
||||
profile,
|
||||
side,
|
||||
meta: {
|
||||
txOrigin: takerRequestQueryParams.txOrigin!,
|
||||
taker: takerRequestQueryParams.takerAddress,
|
||||
client: integratorKey,
|
||||
},
|
||||
};
|
||||
|
||||
// specify a comparison price if it exists
|
||||
if (altComparisonPrice) {
|
||||
data.meta.existingOrder = {
|
||||
price: altComparisonPrice,
|
||||
};
|
||||
}
|
||||
|
||||
// need to specify amount or value
|
||||
// amount is units of the base asset
|
||||
// value is units of the quote asset
|
||||
let requestSize: string;
|
||||
if (takerRequestQueryParams.buyAmountBaseUnits) {
|
||||
requestSize = Web3Wrapper.toUnitAmount(
|
||||
new BigNumber(takerRequestQueryParams.buyAmountBaseUnits),
|
||||
takerRequestQueryParams.buyTokenAddress === altPair.baseAsset
|
||||
? altPair.baseAssetDecimals
|
||||
: altPair.quoteAssetDecimals,
|
||||
).toString();
|
||||
if (takerRequestQueryParams.buyTokenAddress === altPair.baseAsset) {
|
||||
data.amount = requestSize;
|
||||
// add to 'existing order' if there is a comparison price
|
||||
if (data.meta.existingOrder) {
|
||||
data.meta.existingOrder.amount = requestSize;
|
||||
}
|
||||
} else {
|
||||
data.value = requestSize;
|
||||
// add to 'existing order' if there is a comparison price
|
||||
if (data.meta.existingOrder) {
|
||||
data.meta.existingOrder.value = requestSize;
|
||||
}
|
||||
}
|
||||
} else if (takerRequestQueryParams.sellAmountBaseUnits) {
|
||||
requestSize = Web3Wrapper.toUnitAmount(
|
||||
new BigNumber(takerRequestQueryParams.sellAmountBaseUnits),
|
||||
takerRequestQueryParams.sellTokenAddress === altPair.baseAsset
|
||||
? altPair.baseAssetDecimals
|
||||
: altPair.quoteAssetDecimals,
|
||||
).toString();
|
||||
if (takerRequestQueryParams.sellTokenAddress === altPair.baseAsset) {
|
||||
data.amount = requestSize;
|
||||
if (data.meta.existingOrder) {
|
||||
data.meta.existingOrder.amount = requestSize;
|
||||
}
|
||||
} else {
|
||||
data.value = requestSize;
|
||||
if (data.meta.existingOrder) {
|
||||
data.meta.existingOrder.value = requestSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axiosInstance.post(`${url}/quotes`, data, {
|
||||
headers: { Authorization: `Bearer ${apiKey}` },
|
||||
timeout: maxResponseTimeMs,
|
||||
});
|
||||
|
||||
if (response.data.status === 'rejected') {
|
||||
throw new Error('alt MM rejected quote');
|
||||
}
|
||||
|
||||
const parsedResponse =
|
||||
quoteModel === 'firm'
|
||||
? parseFirmQuoteResponseFromAltMM(response.data)
|
||||
: parseIndicativeQuoteResponseFromAltMM(response.data, altPair, makerToken, takerToken);
|
||||
|
||||
return {
|
||||
// hack to appease type checking
|
||||
data: (parsedResponse as unknown) as ResponseT,
|
||||
status: response.status,
|
||||
};
|
||||
}
|
@@ -1,6 +1,47 @@
|
||||
import { MAINNET_CURVE_INFOS, MAINNET_SNOWSWAP_INFOS, MAINNET_SWERVE_INFOS } from './constants';
|
||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
|
||||
|
||||
import {
|
||||
KYBER_BRIDGED_LIQUIDITY_PREFIX,
|
||||
MAINNET_CURVE_INFOS,
|
||||
MAINNET_SHELL_POOLS,
|
||||
MAINNET_SNOWSWAP_INFOS,
|
||||
MAINNET_SWERVE_INFOS,
|
||||
MAX_DODOV2_POOLS_QUERIED,
|
||||
MAX_KYBER_RESERVES_QUERIED,
|
||||
} from './constants';
|
||||
import { CurveInfo, SnowSwapInfo, SwerveInfo } 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
.fill(0)
|
||||
.map((_v, i) => new BigNumber(i));
|
||||
}
|
||||
|
||||
// tslint:disable completed-docs
|
||||
export function getShellsForPair(takerToken: string, makerToken: string): string[] {
|
||||
return Object.values(MAINNET_SHELL_POOLS)
|
||||
.filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)))
|
||||
.map(i => i.poolAddress);
|
||||
}
|
||||
|
||||
// tslint:disable completed-docs
|
||||
export function getCurveInfosForPair(takerToken: string, makerToken: string): CurveInfo[] {
|
||||
return Object.values(MAINNET_CURVE_INFOS).filter(c =>
|
@@ -5,8 +5,15 @@ import * as _ from 'lodash';
|
||||
|
||||
import { MarketOperation } from '../../types';
|
||||
|
||||
import { COMPARISON_PRICE_DECIMALS } from './constants';
|
||||
import { ComparisonPrice, ERC20BridgeSource, FeeEstimate, FeeSchedule, MarketSideLiquidity } from './types';
|
||||
import { COMPARISON_PRICE_DECIMALS, SOURCE_FLAGS } from './constants';
|
||||
import {
|
||||
ComparisonPrice,
|
||||
ERC20BridgeSource,
|
||||
ExchangeProxyOverhead,
|
||||
FeeEstimate,
|
||||
FeeSchedule,
|
||||
MarketSideLiquidity,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Takes in an optimizer response and returns a price for RFQT MMs to beat
|
||||
@@ -23,6 +30,7 @@ export function getComparisonPrices(
|
||||
amount: BigNumber,
|
||||
marketSideLiquidity: MarketSideLiquidity,
|
||||
feeSchedule: FeeSchedule,
|
||||
exchangeProxyOverhead: ExchangeProxyOverhead,
|
||||
): ComparisonPrice {
|
||||
let wholeOrder: BigNumber | undefined;
|
||||
let feeInEth: BigNumber | number;
|
||||
@@ -39,9 +47,11 @@ export function getComparisonPrices(
|
||||
return { wholeOrder };
|
||||
} else {
|
||||
try {
|
||||
feeInEth = new BigNumber(
|
||||
const fillFeeInEth = new BigNumber(
|
||||
(feeSchedule[ERC20BridgeSource.Native] as FeeEstimate)({ type: FillQuoteTransformerOrderType.Rfq }),
|
||||
);
|
||||
const exchangeProxyOverheadInEth = new BigNumber(exchangeProxyOverhead(SOURCE_FLAGS.Native));
|
||||
feeInEth = fillFeeInEth.plus(exchangeProxyOverheadInEth);
|
||||
} catch {
|
||||
logUtils.warn('Native order fee schedule requires fill data');
|
||||
|
||||
@@ -50,10 +60,10 @@ export function getComparisonPrices(
|
||||
}
|
||||
|
||||
// Calc native order fee penalty in output unit (maker units for sells, taker unit for buys)
|
||||
const feePenalty = !marketSideLiquidity.ethToOutputRate.isZero()
|
||||
? marketSideLiquidity.ethToOutputRate.times(feeInEth)
|
||||
const feePenalty = !marketSideLiquidity.outputAmountPerEth.isZero()
|
||||
? marketSideLiquidity.outputAmountPerEth.times(feeInEth)
|
||||
: // if it's a sell, the input token is the taker token
|
||||
marketSideLiquidity.ethToInputRate
|
||||
marketSideLiquidity.inputAmountPerEth
|
||||
.times(feeInEth)
|
||||
.times(marketSideLiquidity.side === MarketOperation.Sell ? adjustedRate : adjustedRate.pow(-1));
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { BridgeContractAddresses } from '../../types';
|
||||
import { TokenAdjacencyGraphBuilder } from '../token_adjacency_graph_builder';
|
||||
|
||||
import { SourceFilters } from './source_filters';
|
||||
import {
|
||||
@@ -19,11 +19,25 @@ import {
|
||||
MultiHopFillData,
|
||||
SnowSwapFillData,
|
||||
SushiSwapFillData,
|
||||
TokenAdjacencyGraph,
|
||||
UniswapV2FillData,
|
||||
} from './types';
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers no-bitwise
|
||||
|
||||
export const ERC20_PROXY_ID = '0xf47261b0';
|
||||
export const WALLET_SIGNATURE = '0x04';
|
||||
export const ONE_ETHER = new BigNumber(1e18);
|
||||
export const NEGATIVE_INF = new BigNumber('-Infinity');
|
||||
export const POSITIVE_INF = new BigNumber('Infinity');
|
||||
export const ZERO_AMOUNT = new BigNumber(0);
|
||||
export const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
||||
export const ONE_HOUR_IN_SECONDS = 60 * 60;
|
||||
export const ONE_SECOND_MS = 1000;
|
||||
export const NULL_BYTES = '0x';
|
||||
export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
export const COMPARISON_PRICE_DECIMALS = 10;
|
||||
|
||||
/**
|
||||
* Valid sources for market sell.
|
||||
*/
|
||||
@@ -44,9 +58,11 @@ export const SELL_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.Shell,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.DodoV2,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -69,9 +85,11 @@ export const BUY_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.DodoV2,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -89,6 +107,23 @@ export const SOURCE_FLAGS: { [source in ERC20BridgeSource]: number } = Object.as
|
||||
...Object.values(ERC20BridgeSource).map((source: ERC20BridgeSource, index) => ({ [source]: 1 << index })),
|
||||
);
|
||||
|
||||
const MIRROR_WRAPPED_TOKENS = {
|
||||
mAAPL: '0xd36932143f6ebdedd872d5fb0651f4b72fd15a84',
|
||||
mSLV: '0x9d1555d8cb3c846bb4f7d5b1b1080872c3166676',
|
||||
mIAU: '0x1d350417d9787e000cc1b95d70e9536dcd91f373',
|
||||
mAMZN: '0x0cae9e4d663793c2a2a0b211c1cf4bbca2b9caa7',
|
||||
mGOOGL: '0x4b70ccd1cf9905be1faed025eadbd3ab124efe9a',
|
||||
mTSLA: '0x21ca39943e91d704678f5d00b6616650f066fd63',
|
||||
mQQQ: '0x13b02c8de71680e71f0820c996e4be43c2f57d15',
|
||||
mTWTR: '0xedb0414627e6f1e3f082de65cd4f9c693d78cca9',
|
||||
mMSFT: '0x41bbedd7286daab5910a1f15d12cbda839852bd7',
|
||||
mNFLX: '0xc8d674114bac90148d11d3c1d33c61835a0f9dcd',
|
||||
mBABA: '0x676ce85f66adb8d7b8323aeefe17087a3b8cb363',
|
||||
mUSO: '0x31c63146a635eb7465e5853020b39713ac356991',
|
||||
mVIXY: '0xf72fcd9dcf0190923fadd44811e240ef4533fc86',
|
||||
mLUNA: '0xd2877702675e6ceb975b4a1dff9fb7baf4c91ea9',
|
||||
};
|
||||
|
||||
// Mainnet tokens
|
||||
// Not an exhaustive list, just enough so we don't repeat ourselves
|
||||
export const TOKENS = {
|
||||
@@ -106,7 +141,6 @@ export const TOKENS = {
|
||||
mUSD: '0xe2f2a5c287993345a840db3b0845fbc70f5935a5',
|
||||
USDN: '0x674c6ad92fd080e4004b2312b45f796a192d27a0',
|
||||
dUSD: '0x5bc25f649fc4e26069ddf4cf4010f9f706c23831',
|
||||
UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd',
|
||||
// Bitcoins
|
||||
WBTC: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
|
||||
RenBTC: '0xeb4c2781e4eba804ce9a9803c67d0893436bb27d',
|
||||
@@ -125,6 +159,11 @@ export const TOKENS = {
|
||||
EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8',
|
||||
sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620',
|
||||
sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb',
|
||||
LINK: '0x514910771af9ca656af840dff83e8264ecf986ca',
|
||||
// Mirror Protocol
|
||||
UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd',
|
||||
MIR: '0x09a3ecafa817268f77be1283176b946c4ff2e608',
|
||||
...MIRROR_WRAPPED_TOKENS,
|
||||
};
|
||||
|
||||
export const POOLS = {
|
||||
@@ -156,6 +195,22 @@ export const POOLS = {
|
||||
curve_aave: '0xdebf20617708857ebe4f679508e7b7863a8a8eee', // 25.aave
|
||||
};
|
||||
|
||||
export const DEFAULT_INTERMEDIATE_TOKENS = [TOKENS.WETH, TOKENS.USDT, TOKENS.DAI, TOKENS.USDC, TOKENS.WBTC];
|
||||
|
||||
export const DEFAULT_TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = new TokenAdjacencyGraphBuilder({
|
||||
default: DEFAULT_INTERMEDIATE_TOKENS,
|
||||
})
|
||||
// Mirror Protocol
|
||||
.tap(builder => {
|
||||
builder
|
||||
.add(TOKENS.MIR, TOKENS.UST)
|
||||
.add(TOKENS.UST, [TOKENS.MIR, ...Object.values(MIRROR_WRAPPED_TOKENS)])
|
||||
.add(TOKENS.USDT, TOKENS.UST);
|
||||
Object.values(MIRROR_WRAPPED_TOKENS).forEach(t => builder.add(t, TOKENS.UST));
|
||||
})
|
||||
// Build
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Mainnet Curve configuration
|
||||
* The tokens are in order of their index, which each curve defines
|
||||
@@ -413,6 +468,8 @@ export const MAINNET_UNISWAP_V1_ROUTER = '0xc0a47dfe034b400b47bdad5fecda2621de6c
|
||||
export const MAINNET_UNISWAP_V2_ROUTER = '0xf164fc0ec4e93095b804a4795bbe1e041497b92a';
|
||||
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f';
|
||||
export const MAINNET_CRYPTO_COM_ROUTER = '0xceb90e4c17d626be0facd78b79c9c87d7ca181b3';
|
||||
export const MAINNET_LINKSWAP_ROUTER = '0xa7ece0911fe8c60bff9e99f8fafcdbe56e07aff1';
|
||||
|
||||
export const MAINNET_MSTABLE_ROUTER = '0xe2f2a5c287993345a840db3b0845fbc70f5935a5';
|
||||
export const MAINNET_OASIS_ROUTER = '0x794e6e91555438afc3ccf1c5076a74f42133d08d';
|
||||
|
||||
@@ -421,6 +478,15 @@ export const MAINNET_MOONISWAP_V2_REGISTRY = '0xc4a8b7e29e3c8ec560cd4945c1cf3461
|
||||
export const MAINNET_MOONISWAP_V2_1_REGISTRY = '0xbaf9a5d4b0052359326a6cdab54babaa3a3a9643';
|
||||
|
||||
export const MAINNET_DODO_HELPER = '0x533da777aedce766ceae696bf90f8541a4ba80eb';
|
||||
export const MAINNET_DODOV2_PRIVATE_POOL_FACTORY = '0x6b4fa0bc61eddc928e0df9c7f01e407bfcd3e5ef';
|
||||
export const MAINNET_DODOV2_VENDING_MACHINE_FACTORY = '0x72d220ce168c4f361dd4dee5d826a01ad8598f6c';
|
||||
export const MAX_DODOV2_POOLS_QUERIED = 3;
|
||||
|
||||
export const CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID: { [id: string]: string } = {
|
||||
'1': '0x7a6F6a048fE2Dc1397ABa0bf7879d3eacF371C53',
|
||||
'3': '0xAa213dcDFbF104e08cbAeC3d1628eD197553AfCc',
|
||||
'1337': NULL_ADDRESS,
|
||||
};
|
||||
|
||||
export const MAINNET_SHELL_POOLS = {
|
||||
StableCoins: {
|
||||
@@ -437,73 +503,6 @@ export const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/ba
|
||||
export const BALANCER_TOP_POOLS_FETCHED = 250;
|
||||
export const BALANCER_MAX_POOLS_FETCHED = 3;
|
||||
|
||||
export const ERC20_PROXY_ID = '0xf47261b0';
|
||||
export const WALLET_SIGNATURE = '0x04';
|
||||
export const ONE_ETHER = new BigNumber(1e18);
|
||||
export const NEGATIVE_INF = new BigNumber('-Infinity');
|
||||
export const POSITIVE_INF = new BigNumber('Infinity');
|
||||
export const ZERO_AMOUNT = new BigNumber(0);
|
||||
export const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
||||
export const ONE_HOUR_IN_SECONDS = 60 * 60;
|
||||
export const ONE_SECOND_MS = 1000;
|
||||
export const NULL_BYTES = '0x';
|
||||
export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
export const COMPARISON_PRICE_DECIMALS = 10;
|
||||
|
||||
const EMPTY_BRIDGE_ADDRESSES: BridgeContractAddresses = {
|
||||
uniswapBridge: NULL_ADDRESS,
|
||||
uniswapV2Bridge: NULL_ADDRESS,
|
||||
eth2DaiBridge: NULL_ADDRESS,
|
||||
kyberBridge: NULL_ADDRESS,
|
||||
curveBridge: NULL_ADDRESS,
|
||||
multiBridge: NULL_ADDRESS,
|
||||
balancerBridge: NULL_ADDRESS,
|
||||
bancorBridge: NULL_ADDRESS,
|
||||
mStableBridge: NULL_ADDRESS,
|
||||
mooniswapBridge: NULL_ADDRESS,
|
||||
sushiswapBridge: NULL_ADDRESS,
|
||||
shellBridge: NULL_ADDRESS,
|
||||
dodoBridge: NULL_ADDRESS,
|
||||
creamBridge: NULL_ADDRESS,
|
||||
snowswapBridge: NULL_ADDRESS,
|
||||
swerveBridge: NULL_ADDRESS,
|
||||
cryptoComBridge: NULL_ADDRESS,
|
||||
};
|
||||
|
||||
export const BRIDGE_ADDRESSES_BY_CHAIN: { [chainId in ChainId]: BridgeContractAddresses } = {
|
||||
[ChainId.Mainnet]: {
|
||||
uniswapBridge: '0x36691c4f426eb8f42f150ebde43069a31cb080ad',
|
||||
uniswapV2Bridge: '0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48',
|
||||
kyberBridge: '0xadd97271402590564ddd8ad23cb5317b1fb0fffb',
|
||||
eth2DaiBridge: '0x991c745401d5b5e469b8c3e2cb02c748f08754f1',
|
||||
curveBridge: '0x1796cd592d19e3bcd744fbb025bb61a6d8cb2c09',
|
||||
multiBridge: '0xc03117a8c9bde203f70aa911cb64a7a0df5ba1e1',
|
||||
balancerBridge: '0xfe01821ca163844203220cd08e4f2b2fb43ae4e4',
|
||||
bancorBridge: '0xc880c252db7c51f74161633338a3bdafa8e65276',
|
||||
mStableBridge: '0x2bf04fcea05f0989a14d9afa37aa376baca6b2b3',
|
||||
mooniswapBridge: '0x02b7eca484ad960fca3f7709e0b2ac81eec3069c',
|
||||
sushiswapBridge: '0x47ed0262a0b688dcb836d254c6a2e96b6c48a9f5',
|
||||
shellBridge: '0xf1c0811e3788caae7dbfae43da9d9131b1a8a148',
|
||||
dodoBridge: '0xe9da66965a9344aab2167e6813c03f043cc7a6ca',
|
||||
creamBridge: '0xb9d4bf2c8dab828f4ffb656acdb6c2b497d44f25',
|
||||
swerveBridge: '0xf9786d5eb1de47fa56a8f7bb387653c6d410bfee',
|
||||
snowswapBridge: '0xb1dbe83d15236ec10fdb214c6b89774b454754fd',
|
||||
cryptoComBridge: '0x015850307f6aab4ac6631923ceefe71b57492c9b',
|
||||
},
|
||||
[ChainId.Kovan]: {
|
||||
...EMPTY_BRIDGE_ADDRESSES,
|
||||
uniswapBridge: '0x0e85f89f29998df65402391478e5924700c0079d',
|
||||
uniswapV2Bridge: '0x7b3530a635d099de0534dc27e46cd7c57578c3c8',
|
||||
eth2DaiBridge: '0x2d47147429b474d2e4f83e658015858a1312ed5b',
|
||||
kyberBridge: '0xaecfa25920f892b6eb496e1f6e84037f59da7f44',
|
||||
curveBridge: '0x81c0ab53a7352d2e97f682a37cba44e54647eefb',
|
||||
balancerBridge: '0x407b4128e9ecad8769b2332312a9f655cb9f5f3a',
|
||||
},
|
||||
[ChainId.Rinkeby]: EMPTY_BRIDGE_ADDRESSES,
|
||||
[ChainId.Ropsten]: EMPTY_BRIDGE_ADDRESSES,
|
||||
[ChainId.Ganache]: EMPTY_BRIDGE_ADDRESSES,
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculated gross gas cost of the underlying exchange.
|
||||
* The cost of switching from one source to another, assuming
|
||||
@@ -513,9 +512,13 @@ export const BRIDGE_ADDRESSES_BY_CHAIN: { [chainId in ChainId]: BridgeContractAd
|
||||
*/
|
||||
// tslint:disable:custom-no-magic-numbers
|
||||
export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
[ERC20BridgeSource.Native]: _fillData => {
|
||||
// const nativeFillData = (_fillData as NativeRfqOrderFillData|NativeLimitOrderFillData)
|
||||
return 100e3;
|
||||
[ERC20BridgeSource.Native]: fillData => {
|
||||
// TODO jacob re-order imports so there is no circular rependency with SignedNativeOrder
|
||||
const nativeFillData = fillData as ({ type: FillQuoteTransformerOrderType });
|
||||
return nativeFillData && nativeFillData.type === FillQuoteTransformerOrderType.Limit
|
||||
? PROTOCOL_FEE_MULTIPLIER.plus(100e3).toNumber()
|
||||
: // TODO jacob revisit wth v4 LimitOrders
|
||||
100e3;
|
||||
},
|
||||
[ERC20BridgeSource.Uniswap]: () => 90e3,
|
||||
[ERC20BridgeSource.LiquidityProvider]: fillData => {
|
||||
@@ -581,8 +584,17 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
},
|
||||
[ERC20BridgeSource.CryptoCom]: (fillData?: FillData) => {
|
||||
// TODO: Different base cost if to/from ETH.
|
||||
let gas = 90e3 + 20e3 + 60e3; // temporary allowance diff, unrolled FQT
|
||||
const path = (fillData as SushiSwapFillData).tokenAddressPath;
|
||||
let gas = 90e3;
|
||||
const path = (fillData as UniswapV2FillData).tokenAddressPath;
|
||||
if (path.length > 2) {
|
||||
gas += (path.length - 2) * 60e3; // +60k for each hop.
|
||||
}
|
||||
return gas;
|
||||
},
|
||||
[ERC20BridgeSource.Linkswap]: (fillData?: FillData) => {
|
||||
// TODO: Different base cost if to/from ETH.
|
||||
let gas = 90e3;
|
||||
const path = (fillData as UniswapV2FillData).tokenAddressPath;
|
||||
if (path.length > 2) {
|
||||
gas += (path.length - 2) * 60e3; // +60k for each hop.
|
||||
}
|
||||
@@ -610,6 +622,7 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
// sell quote requires additional calculation and overhead
|
||||
return isSellBase ? 180e3 : 300e3;
|
||||
},
|
||||
[ERC20BridgeSource.DodoV2]: (_fillData?: FillData) => 100e3,
|
||||
[ERC20BridgeSource.SnowSwap]: fillData => {
|
||||
switch ((fillData as SnowSwapFillData).pool.poolAddress.toLowerCase()) {
|
||||
case '0xbf7ccd6c446acfcc5df023043f2167b62e81899b':
|
||||
@@ -630,15 +643,9 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_FEE_SCHEDULE: Required<FeeSchedule> = Object.assign(
|
||||
{},
|
||||
...(Object.keys(DEFAULT_GAS_SCHEDULE) as ERC20BridgeSource[]).map(k => ({
|
||||
[k]:
|
||||
k === ERC20BridgeSource.Native
|
||||
? (fillData: FillData) => PROTOCOL_FEE_MULTIPLIER.plus(DEFAULT_GAS_SCHEDULE[k](fillData))
|
||||
: (fillData: FillData) => DEFAULT_GAS_SCHEDULE[k](fillData),
|
||||
})),
|
||||
);
|
||||
export const DEFAULT_FEE_SCHEDULE: Required<FeeSchedule> = { ...DEFAULT_GAS_SCHEDULE };
|
||||
|
||||
export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(20000);
|
||||
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
|
||||
|
@@ -16,8 +16,8 @@ export function createFills(opts: {
|
||||
orders?: NativeOrderWithFillableAmounts[];
|
||||
dexQuotes?: DexSample[][];
|
||||
targetInput?: BigNumber;
|
||||
ethToOutputRate?: BigNumber;
|
||||
ethToInputRate?: BigNumber;
|
||||
outputAmountPerEth?: BigNumber;
|
||||
inputAmountPerEth?: BigNumber;
|
||||
excludedSources?: ERC20BridgeSource[];
|
||||
feeSchedule?: FeeSchedule;
|
||||
}): Fill[][] {
|
||||
@@ -26,20 +26,20 @@ export function createFills(opts: {
|
||||
const feeSchedule = opts.feeSchedule || {};
|
||||
const orders = opts.orders || [];
|
||||
const dexQuotes = opts.dexQuotes || [];
|
||||
const ethToOutputRate = opts.ethToOutputRate || ZERO_AMOUNT;
|
||||
const ethToInputRate = opts.ethToInputRate || ZERO_AMOUNT;
|
||||
const outputAmountPerEth = opts.outputAmountPerEth || ZERO_AMOUNT;
|
||||
const inputAmountPerEth = opts.inputAmountPerEth || ZERO_AMOUNT;
|
||||
// Create native fills.
|
||||
const nativeFills = nativeOrdersToFills(
|
||||
side,
|
||||
orders.filter(o => o.fillableTakerAmount.isGreaterThan(0)),
|
||||
opts.targetInput,
|
||||
ethToOutputRate,
|
||||
ethToInputRate,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
feeSchedule,
|
||||
);
|
||||
// Create DEX fills.
|
||||
const dexFills = dexQuotes.map(singleSourceSamples =>
|
||||
dexSamplesToFills(side, singleSourceSamples, ethToOutputRate, ethToInputRate, feeSchedule),
|
||||
dexSamplesToFills(side, singleSourceSamples, outputAmountPerEth, inputAmountPerEth, feeSchedule),
|
||||
);
|
||||
return [...dexFills, nativeFills]
|
||||
.map(p => clipFillsToInput(p, opts.targetInput))
|
||||
@@ -75,8 +75,8 @@ function nativeOrdersToFills(
|
||||
side: MarketOperation,
|
||||
orders: NativeOrderWithFillableAmounts[],
|
||||
targetInput: BigNumber = POSITIVE_INF,
|
||||
ethToOutputRate: BigNumber,
|
||||
ethToInputRate: BigNumber,
|
||||
outputAmountPerEth: BigNumber,
|
||||
inputAmountPerEth: BigNumber,
|
||||
fees: FeeSchedule,
|
||||
): Fill[] {
|
||||
const sourcePathId = hexUtils.random();
|
||||
@@ -89,9 +89,9 @@ function nativeOrdersToFills(
|
||||
const input = side === MarketOperation.Sell ? takerAmount : makerAmount;
|
||||
const output = side === MarketOperation.Sell ? makerAmount : takerAmount;
|
||||
const fee = fees[ERC20BridgeSource.Native] === undefined ? 0 : fees[ERC20BridgeSource.Native]!(o);
|
||||
const outputPenalty = !ethToOutputRate.isZero()
|
||||
? ethToOutputRate.times(fee)
|
||||
: ethToInputRate.times(fee).times(output.dividedToIntegerBy(input));
|
||||
const outputPenalty = !outputAmountPerEth.isZero()
|
||||
? outputAmountPerEth.times(fee)
|
||||
: inputAmountPerEth.times(fee).times(output.dividedToIntegerBy(input));
|
||||
// targetInput can be less than the order size
|
||||
// whilst the penalty is constant, it affects the adjusted output
|
||||
// only up until the target has been exhausted.
|
||||
@@ -135,8 +135,8 @@ function nativeOrdersToFills(
|
||||
function dexSamplesToFills(
|
||||
side: MarketOperation,
|
||||
samples: DexSample[],
|
||||
ethToOutputRate: BigNumber,
|
||||
ethToInputRate: BigNumber,
|
||||
outputAmountPerEth: BigNumber,
|
||||
inputAmountPerEth: BigNumber,
|
||||
fees: FeeSchedule,
|
||||
): Fill[] {
|
||||
const sourcePathId = hexUtils.random();
|
||||
@@ -156,9 +156,9 @@ function dexSamplesToFills(
|
||||
let penalty = ZERO_AMOUNT;
|
||||
if (i === 0) {
|
||||
// Only the first fill in a DEX path incurs a penalty.
|
||||
penalty = !ethToOutputRate.isZero()
|
||||
? ethToOutputRate.times(fee)
|
||||
: ethToInputRate.times(fee).times(output.dividedToIntegerBy(input));
|
||||
penalty = !outputAmountPerEth.isZero()
|
||||
? outputAmountPerEth.times(fee)
|
||||
: inputAmountPerEth.times(fee).times(output.dividedToIntegerBy(input));
|
||||
}
|
||||
const adjustedOutput = side === MarketOperation.Sell ? output.minus(penalty) : output.plus(penalty);
|
||||
|
||||
|
@@ -30,7 +30,8 @@ import {
|
||||
import { createFills } from './fills';
|
||||
import { getBestTwoHopQuote } from './multihop_utils';
|
||||
import { createOrdersFromTwoHopSample } from './orders';
|
||||
import { findOptimalPathAsync } from './path_optimizer';
|
||||
import { PathPenaltyOpts } from './path';
|
||||
import { fillsToSortedPaths, findOptimalPathAsync } from './path_optimizer';
|
||||
import { DexOrderSampler, getSampleAmounts } from './sampler';
|
||||
import { SourceFilters } from './source_filters';
|
||||
import {
|
||||
@@ -167,8 +168,8 @@ export class MarketOperationUtils {
|
||||
[
|
||||
tokenDecimals,
|
||||
orderFillableTakerAmounts,
|
||||
ethToMakerAssetRate,
|
||||
ethToTakerAssetRate,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
dexQuotes,
|
||||
rawTwoHopQuotes,
|
||||
isTxOriginContract,
|
||||
@@ -178,7 +179,9 @@ export class MarketOperationUtils {
|
||||
] = await Promise.all([samplerPromise, offChainBalancerPromise, offChainCreamPromise]);
|
||||
|
||||
// Filter out any invalid two hop quotes where we couldn't find a route
|
||||
const twoHopQuotes = rawTwoHopQuotes.filter(q => q && q.fillData && q.fillData.firstHopSource);
|
||||
const twoHopQuotes = rawTwoHopQuotes.filter(
|
||||
q => q && q.fillData && q.fillData.firstHopSource && q.fillData.secondHopSource,
|
||||
);
|
||||
|
||||
const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
|
||||
|
||||
@@ -193,8 +196,8 @@ export class MarketOperationUtils {
|
||||
inputAmount: takerAmount,
|
||||
inputToken: takerToken,
|
||||
outputToken: makerToken,
|
||||
ethToOutputRate: ethToMakerAssetRate,
|
||||
ethToInputRate: ethToTakerAssetRate,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
quoteSourceFilters,
|
||||
makerTokenDecimals: makerTokenDecimals.toNumber(),
|
||||
takerTokenDecimals: takerTokenDecimals.toNumber(),
|
||||
@@ -302,7 +305,9 @@ export class MarketOperationUtils {
|
||||
] = await Promise.all([samplerPromise, offChainBalancerPromise, offChainCreamPromise]);
|
||||
|
||||
// Filter out any invalid two hop quotes where we couldn't find a route
|
||||
const twoHopQuotes = rawTwoHopQuotes.filter(q => q && q.fillData && q.fillData.firstHopSource);
|
||||
const twoHopQuotes = rawTwoHopQuotes.filter(
|
||||
q => q && q.fillData && q.fillData.firstHopSource && q.fillData.secondHopSource,
|
||||
);
|
||||
|
||||
const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
|
||||
const isRfqSupported = !isTxOriginContract;
|
||||
@@ -317,8 +322,8 @@ export class MarketOperationUtils {
|
||||
inputAmount: makerAmount,
|
||||
inputToken: makerToken,
|
||||
outputToken: takerToken,
|
||||
ethToOutputRate: ethToTakerAssetRate,
|
||||
ethToInputRate: ethToMakerAssetRate,
|
||||
outputAmountPerEth: ethToTakerAssetRate,
|
||||
inputAmountPerEth: ethToMakerAssetRate,
|
||||
quoteSourceFilters,
|
||||
makerTokenDecimals: makerTokenDecimals.toNumber(),
|
||||
takerTokenDecimals: takerTokenDecimals.toNumber(),
|
||||
@@ -388,7 +393,7 @@ export class MarketOperationUtils {
|
||||
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 ethToInputRate = ZERO_AMOUNT;
|
||||
const inputAmountPerEth = ZERO_AMOUNT;
|
||||
|
||||
return Promise.all(
|
||||
batchNativeOrders.map(async (nativeOrders, i) => {
|
||||
@@ -397,7 +402,7 @@ export class MarketOperationUtils {
|
||||
}
|
||||
const { makerToken, takerToken } = nativeOrders[0].order;
|
||||
const orderFillableMakerAmounts = batchOrderFillableMakerAmounts[i];
|
||||
const ethToTakerAssetRate = batchEthToTakerAssetRate[i];
|
||||
const outputAmountPerEth = batchEthToTakerAssetRate[i];
|
||||
const dexQuotes = batchDexQuotes[i];
|
||||
const makerAmount = makerAmounts[i];
|
||||
try {
|
||||
@@ -407,8 +412,8 @@ export class MarketOperationUtils {
|
||||
inputToken: makerToken,
|
||||
outputToken: takerToken,
|
||||
inputAmount: makerAmount,
|
||||
ethToOutputRate: ethToTakerAssetRate,
|
||||
ethToInputRate,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
quoteSourceFilters,
|
||||
makerTokenDecimals: batchTokenDecimals[i][0],
|
||||
takerTokenDecimals: batchTokenDecimals[i][1],
|
||||
@@ -451,8 +456,8 @@ export class MarketOperationUtils {
|
||||
side,
|
||||
inputAmount,
|
||||
quotes,
|
||||
ethToOutputRate,
|
||||
ethToInputRate,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
} = marketSideLiquidity;
|
||||
const { nativeOrders, rfqtIndicativeQuotes, dexQuotes } = quotes;
|
||||
const maxFallbackSlippage = opts.maxFallbackSlippage || 0;
|
||||
@@ -485,25 +490,29 @@ export class MarketOperationUtils {
|
||||
orders: [...nativeOrders, ...augmentedRfqtIndicativeQuotes],
|
||||
dexQuotes,
|
||||
targetInput: inputAmount,
|
||||
ethToOutputRate,
|
||||
ethToInputRate,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
excludedSources: opts.excludedSources,
|
||||
feeSchedule: opts.feeSchedule,
|
||||
});
|
||||
|
||||
// Find the optimal path.
|
||||
const optimizerOpts = {
|
||||
ethToOutputRate,
|
||||
ethToInputRate,
|
||||
const penaltyOpts: PathPenaltyOpts = {
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
exchangeProxyOverhead: opts.exchangeProxyOverhead || (() => ZERO_AMOUNT),
|
||||
};
|
||||
|
||||
// NOTE: For sell quotes input is the taker asset and for buy quotes input is the maker asset
|
||||
const takerTokenToEthRate = side === MarketOperation.Sell ? ethToInputRate : ethToOutputRate;
|
||||
const makerTokenToEthRate = side === MarketOperation.Sell ? ethToOutputRate : ethToInputRate;
|
||||
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;
|
||||
|
||||
// Find the optimal path
|
||||
const optimalPath = await findOptimalPathAsync(side, fills, inputAmount, opts.runLimit, optimizerOpts);
|
||||
const optimalPath = await findOptimalPathAsync(side, fills, inputAmount, opts.runLimit, penaltyOpts);
|
||||
const optimalPathRate = optimalPath ? optimalPath.adjustedRate() : ZERO_AMOUNT;
|
||||
|
||||
const { adjustedRate: bestTwoHopRate, quote: bestTwoHopQuote } = getBestTwoHopQuote(
|
||||
@@ -519,8 +528,9 @@ export class MarketOperationUtils {
|
||||
sourceFlags: SOURCE_FLAGS[ERC20BridgeSource.MultiHop],
|
||||
marketSideLiquidity,
|
||||
adjustedRate: bestTwoHopRate,
|
||||
takerTokenToEthRate,
|
||||
makerTokenToEthRate,
|
||||
unoptimizedPath,
|
||||
takerAmountPerEth,
|
||||
makerAmountPerEth,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -553,8 +563,9 @@ export class MarketOperationUtils {
|
||||
sourceFlags: collapsedPath.sourceFlags,
|
||||
marketSideLiquidity,
|
||||
adjustedRate: optimalPathRate,
|
||||
takerTokenToEthRate,
|
||||
makerTokenToEthRate,
|
||||
unoptimizedPath,
|
||||
takerAmountPerEth,
|
||||
makerAmountPerEth,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -608,6 +619,7 @@ export class MarketOperationUtils {
|
||||
amount,
|
||||
marketSideLiquidity,
|
||||
_opts.feeSchedule,
|
||||
_opts.exchangeProxyOverhead,
|
||||
).wholeOrder;
|
||||
}
|
||||
|
||||
|
@@ -1,20 +0,0 @@
|
||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
|
||||
|
||||
import { KYBER_BRIDGED_LIQUIDITY_PREFIX, MAX_KYBER_RESERVES_QUERIED } from './constants';
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
@@ -39,7 +39,7 @@ export function getBestTwoHopQuote(
|
||||
feeSchedule?: FeeSchedule,
|
||||
exchangeProxyOverhead?: ExchangeProxyOverhead,
|
||||
): { quote: DexSample<MultiHopFillData> | undefined; adjustedRate: BigNumber } {
|
||||
const { side, inputAmount, ethToOutputRate, quotes } = marketSideLiquidity;
|
||||
const { side, inputAmount, outputAmountPerEth, quotes } = marketSideLiquidity;
|
||||
const { twoHopQuotes } = quotes;
|
||||
// Ensure the expected data we require exists. In the case where all hops reverted
|
||||
// or there were no sources included that allowed for multi hop,
|
||||
@@ -57,7 +57,7 @@ export function getBestTwoHopQuote(
|
||||
}
|
||||
const best = filteredQuotes
|
||||
.map(quote =>
|
||||
getTwoHopAdjustedRate(side, quote, inputAmount, ethToOutputRate, feeSchedule, exchangeProxyOverhead),
|
||||
getTwoHopAdjustedRate(side, quote, inputAmount, outputAmountPerEth, feeSchedule, exchangeProxyOverhead),
|
||||
)
|
||||
.reduce(
|
||||
(prev, curr, i) =>
|
||||
@@ -67,7 +67,7 @@ export function getBestTwoHopQuote(
|
||||
side,
|
||||
filteredQuotes[0],
|
||||
inputAmount,
|
||||
ethToOutputRate,
|
||||
outputAmountPerEth,
|
||||
feeSchedule,
|
||||
exchangeProxyOverhead,
|
||||
),
|
||||
|
@@ -118,6 +118,10 @@ export function getERC20BridgeSourceToBridgeSource(source: ERC20BridgeSource): B
|
||||
return BridgeSource.Uniswap;
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
return BridgeSource.UniswapV2;
|
||||
case ERC20BridgeSource.DodoV2:
|
||||
return BridgeSource.DodoV2;
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
return BridgeSource.Linkswap;
|
||||
default:
|
||||
throw new Error(AggregationError.NoBridgeForSource);
|
||||
}
|
||||
@@ -164,6 +168,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData | SushiSwapFillData>)
|
||||
.fillData;
|
||||
bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
|
||||
@@ -180,6 +185,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
const dodoFillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
|
||||
bridgeData = encoder.encode([MAINNET_DODO_HELPER, dodoFillData.poolAddress, dodoFillData.isSellBase]);
|
||||
break;
|
||||
case ERC20BridgeSource.DodoV2:
|
||||
const dodoV2FillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
|
||||
bridgeData = encoder.encode([dodoV2FillData.poolAddress, dodoV2FillData.isSellBase]);
|
||||
break;
|
||||
case ERC20BridgeSource.Shell:
|
||||
const shellFillData = (order as OptimizedMarketBridgeOrder<ShellFillData>).fillData;
|
||||
bridgeData = encoder.encode([shellFillData.poolAddress]);
|
||||
@@ -258,6 +267,10 @@ export const BRIDGE_ENCODERS: {
|
||||
{ name: 'poolAddress', type: 'address' },
|
||||
{ name: 'isSellBase', type: 'bool' },
|
||||
]),
|
||||
[ERC20BridgeSource.DodoV2]: AbiEncoder.create([
|
||||
{ name: 'poolAddress', type: 'address' },
|
||||
{ name: 'isSellBase', type: 'bool' },
|
||||
]),
|
||||
// Curve like
|
||||
[ERC20BridgeSource.Curve]: curveEncoder,
|
||||
[ERC20BridgeSource.Swerve]: curveEncoder,
|
||||
@@ -267,6 +280,7 @@ export const BRIDGE_ENCODERS: {
|
||||
[ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Linkswap]: routerAddressPathEncoder,
|
||||
// Generic pools
|
||||
[ERC20BridgeSource.Shell]: poolEncoder,
|
||||
[ERC20BridgeSource.Mooniswap]: poolEncoder,
|
||||
|
@@ -22,14 +22,14 @@ export interface PathSize {
|
||||
}
|
||||
|
||||
export interface PathPenaltyOpts {
|
||||
ethToOutputRate: BigNumber;
|
||||
ethToInputRate: BigNumber;
|
||||
outputAmountPerEth: BigNumber;
|
||||
inputAmountPerEth: BigNumber;
|
||||
exchangeProxyOverhead: ExchangeProxyOverhead;
|
||||
}
|
||||
|
||||
export const DEFAULT_PATH_PENALTY_OPTS: PathPenaltyOpts = {
|
||||
ethToOutputRate: ZERO_AMOUNT,
|
||||
ethToInputRate: ZERO_AMOUNT,
|
||||
outputAmountPerEth: ZERO_AMOUNT,
|
||||
inputAmountPerEth: ZERO_AMOUNT,
|
||||
exchangeProxyOverhead: () => ZERO_AMOUNT,
|
||||
};
|
||||
|
||||
@@ -131,11 +131,11 @@ export class Path {
|
||||
|
||||
public adjustedSize(): PathSize {
|
||||
const { input, output } = this._adjustedSize;
|
||||
const { exchangeProxyOverhead, ethToOutputRate, ethToInputRate } = this.pathPenaltyOpts;
|
||||
const { exchangeProxyOverhead, outputAmountPerEth, inputAmountPerEth } = this.pathPenaltyOpts;
|
||||
const gasOverhead = exchangeProxyOverhead(this.sourceFlags);
|
||||
const pathPenalty = !ethToOutputRate.isZero()
|
||||
? ethToOutputRate.times(gasOverhead)
|
||||
: ethToInputRate.times(gasOverhead).times(output.dividedToIntegerBy(input));
|
||||
const pathPenalty = !outputAmountPerEth.isZero()
|
||||
? outputAmountPerEth.times(gasOverhead)
|
||||
: inputAmountPerEth.times(gasOverhead).times(output.dividedToIntegerBy(input));
|
||||
return {
|
||||
input,
|
||||
output: this.side === MarketOperation.Sell ? output.minus(pathPenalty) : output.plus(pathPenalty),
|
||||
|
@@ -13,7 +13,7 @@ export function getTwoHopAdjustedRate(
|
||||
side: MarketOperation,
|
||||
twoHopQuote: DexSample<MultiHopFillData>,
|
||||
targetInput: BigNumber,
|
||||
ethToOutputRate: BigNumber,
|
||||
outputAmountPerEth: BigNumber,
|
||||
fees: FeeSchedule = {},
|
||||
exchangeProxyOverhead: ExchangeProxyOverhead = () => ZERO_AMOUNT,
|
||||
): BigNumber {
|
||||
@@ -21,7 +21,7 @@ export function getTwoHopAdjustedRate(
|
||||
if (input.isLessThan(targetInput) || output.isZero()) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const penalty = ethToOutputRate.times(
|
||||
const penalty = outputAmountPerEth.times(
|
||||
exchangeProxyOverhead(SOURCE_FLAGS.MultiHop).plus(fees[ERC20BridgeSource.MultiHop]!(fillData)),
|
||||
);
|
||||
const adjustedOutput = side === MarketOperation.Sell ? output.minus(penalty) : output.plus(penalty);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user