Compare commits
34 Commits
poc/boost
...
protocol@8
Author | SHA1 | Date | |
---|---|---|---|
|
859c36cb10 | ||
|
3e34386812 | ||
|
a35af11981 | ||
|
59eabec71e | ||
|
bf4c7e7d50 | ||
|
fd098ca4df | ||
|
c360f8d8fd | ||
|
b358559421 | ||
|
df5aad8e8e | ||
|
8dbf79db59 | ||
|
1839608e84 | ||
|
6e3e795b8b | ||
|
d9c410a7e3 | ||
|
609727afe8 | ||
|
8a5c74c0b4 | ||
|
cd93f3b07e | ||
|
8397b12de6 | ||
|
3f85acec3a | ||
|
d6a9e3d600 | ||
|
361569ac2f | ||
|
719664c145 | ||
|
f800d6c24c | ||
|
a9a81bcafb | ||
|
4280307a15 | ||
|
7b57d3ae51 | ||
|
8a8a5bbda0 | ||
|
76987c8db1 | ||
|
6f8971cc42 | ||
|
71ab882143 | ||
|
5a4961c8d9 | ||
|
4c4fb99d87 | ||
|
872abf09e9 | ||
|
f10bfe7d04 | ||
|
a74d8deff3 |
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "3.7.17",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.7.16",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.7.17 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.16 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.7.16",
|
||||
"version": "3.7.17",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,10 +52,10 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contract-wrappers": "^13.17.2",
|
||||
"@0x/contract-wrappers": "^13.17.3",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -80,11 +80,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-erc1155": "^2.1.34",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-erc721": "^3.1.34",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/contracts-erc1155": "^2.1.35",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-erc721": "^3.1.35",
|
||||
"@0x/contracts-exchange-libs": "^4.3.35",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "1.1.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "1.1.34",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.35 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-broker",
|
||||
"version": "1.1.34",
|
||||
"version": "1.1.35",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,14 +52,14 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-erc721": "^3.1.34",
|
||||
"@0x/contracts-exchange": "^3.2.35",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-erc721": "^3.1.35",
|
||||
"@0x/contracts-exchange": "^3.2.36",
|
||||
"@0x/contracts-exchange-libs": "^4.3.35",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
@@ -85,7 +85,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"ethereum-types": "^3.5.0"
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "3.1.36",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.1.35",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.36 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.1.35",
|
||||
"version": "3.1.36",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,12 +53,12 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-dev-utils": "^1.3.33",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-dev-utils": "^1.3.34",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
@@ -84,10 +84,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/contracts-exchange": "^3.2.35",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contract-addresses": "^6.5.0",
|
||||
"@0x/contracts-exchange": "^3.2.36",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/json-schemas": "^6.1.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "1.3.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "1.3.33",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.3.34 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.33 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.3.33",
|
||||
"version": "1.3.34",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -43,10 +43,10 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "2.1.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "2.1.34",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.1.35 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.1.34",
|
||||
"version": "2.1.35",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,7 +54,7 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -81,7 +81,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"lodash": "^4.17.11"
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "3.3.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.3.13",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.3.14 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.13 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.3.13",
|
||||
"version": "3.3.14",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,8 +53,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "3.1.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.1.34",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.35 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.1.34",
|
||||
"version": "3.1.35",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,8 +54,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "4.2.36",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.2.35",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.36 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.2.35",
|
||||
"version": "4.2.36",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,18 +53,18 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-dev-utils": "^1.3.33",
|
||||
"@0x/contracts-erc1155": "^2.1.34",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-erc721": "^3.1.34",
|
||||
"@0x/contracts-exchange": "^3.2.35",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-dev-utils": "^1.3.34",
|
||||
"@0x/contracts-erc1155": "^2.1.35",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-erc721": "^3.1.35",
|
||||
"@0x/contracts-exchange": "^3.2.36",
|
||||
"@0x/contracts-exchange-libs": "^4.3.35",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "4.3.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.3.34",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.3.35 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.3.34",
|
||||
"version": "4.3.35",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -81,9 +81,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "3.2.36",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.2.35",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.36 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.2.35",
|
||||
"version": "3.2.36",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,13 +53,13 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-exchange-libs": "^4.3.35",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-multisig": "^4.1.35",
|
||||
"@0x/contracts-staking": "^2.0.42",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-multisig": "^4.1.36",
|
||||
"@0x/contracts-staking": "^2.0.43",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -89,11 +89,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-dev-utils": "^1.3.33",
|
||||
"@0x/contracts-erc1155": "^2.1.34",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-erc721": "^3.1.34",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/contracts-dev-utils": "^1.3.34",
|
||||
"@0x/contracts-erc1155": "^2.1.35",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-erc721": "^3.1.35",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "6.2.30",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "6.2.29",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.2.30 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.2.29 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "6.2.29",
|
||||
"version": "6.2.30",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,16 +53,16 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-dev-utils": "^1.3.33",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-erc721": "^3.1.34",
|
||||
"@0x/contracts-exchange": "^3.2.35",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-dev-utils": "^1.3.34",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-erc721": "^3.1.35",
|
||||
"@0x/contracts-exchange": "^3.2.36",
|
||||
"@0x/contracts-exchange-libs": "^4.3.35",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
@@ -91,7 +91,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"ethereum-types": "^3.5.0"
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-integrations",
|
||||
"version": "2.7.53",
|
||||
"version": "2.7.62",
|
||||
"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.6.0",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/contract-wrappers": "^13.17.2",
|
||||
"@0x/contracts-broker": "^1.1.34",
|
||||
"@0x/contracts-coordinator": "^3.1.35",
|
||||
"@0x/contracts-dev-utils": "^1.3.33",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.35",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/contracts-extensions": "^6.2.29",
|
||||
"@0x/contract-addresses": "^6.5.0",
|
||||
"@0x/contract-wrappers": "^13.17.3",
|
||||
"@0x/contracts-broker": "^1.1.35",
|
||||
"@0x/contracts-coordinator": "^3.1.36",
|
||||
"@0x/contracts-dev-utils": "^1.3.34",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.36",
|
||||
"@0x/contracts-exchange-libs": "^4.3.35",
|
||||
"@0x/contracts-extensions": "^6.2.30",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/coordinator-server": "^1.0.5",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/migrations": "^8.0.11",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/protocol-utils": "^1.7.2",
|
||||
"@0x/migrations": "^8.0.12",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/protocol-utils": "^1.8.0",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
@@ -93,17 +93,17 @@
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/asset-swapper": "^6.18.2",
|
||||
"@0x/asset-swapper": "^16.24.0",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc1155": "^2.1.34",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-erc721": "^3.1.34",
|
||||
"@0x/contracts-exchange": "^3.2.35",
|
||||
"@0x/contracts-multisig": "^4.1.35",
|
||||
"@0x/contracts-staking": "^2.0.42",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-zero-ex": "^0.26.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-erc1155": "^2.1.35",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-erc721": "^3.1.35",
|
||||
"@0x/contracts-exchange": "^3.2.36",
|
||||
"@0x/contracts-multisig": "^4.1.36",
|
||||
"@0x/contracts-staking": "^2.0.43",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-zero-ex": "^0.27.0",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "4.1.36",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.1.35",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.36 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-multisig",
|
||||
"version": "4.1.35",
|
||||
"version": "4.1.36",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,11 +50,11 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "2.0.43",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "2.0.42",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.43 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.42 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-staking",
|
||||
"version": "2.0.42",
|
||||
"version": "2.0.43",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,14 +54,14 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-dev-utils": "^1.3.33",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-dev-utils": "^1.3.34",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-exchange-libs": "^4.3.35",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/contracts-utils": "^4.7.14",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"ethereum-types": "^3.5.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "5.4.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "5.4.5",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.4.6 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.5 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.4.5",
|
||||
"version": "5.4.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,10 +44,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.5.0",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/json-schemas": "^6.1.3",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/sol-coverage": "^4.0.37",
|
||||
"@0x/sol-profiler": "^4.1.27",
|
||||
"@0x/sol-trace": "^3.0.37",
|
||||
|
@@ -1,4 +1,14 @@
|
||||
[
|
||||
{
|
||||
"version": "1.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added proposal 1 params and test",
|
||||
"pr": 298
|
||||
}
|
||||
],
|
||||
"timestamp": 1628225642
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "1.2.3",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.3.0 - _August 6, 2021_
|
||||
|
||||
* Added proposal 1 params and test (#298)
|
||||
|
||||
## v1.2.3 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-treasury",
|
||||
"version": "1.2.3",
|
||||
"version": "1.3.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -47,12 +47,12 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contract-addresses": "^6.5.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.17",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-staking": "^2.0.42",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-staking": "^2.0.43",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
@@ -73,7 +73,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/protocol-utils": "^1.7.2",
|
||||
"@0x/protocol-utils": "^1.8.0",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
File diff suppressed because one or more lines are too long
@@ -151,4 +151,72 @@ blockchainTests.fork.skip('Treasury proposal mainnet fork tests', env => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Proposal 1', () => {
|
||||
it('works', async () => {
|
||||
const proposal = proposals[1];
|
||||
let executionEpoch: BigNumber;
|
||||
if (proposal.executionEpoch) {
|
||||
executionEpoch = proposal.executionEpoch;
|
||||
} else {
|
||||
const currentEpoch = await staking.currentEpoch().callAsync();
|
||||
executionEpoch = currentEpoch.plus(2);
|
||||
}
|
||||
const pools = await querySubgraphAsync(PROPOSER);
|
||||
const proposeTx = treasury.propose(proposal.actions, executionEpoch, proposal.description, pools);
|
||||
|
||||
const calldata = proposeTx.getABIEncodedTransactionData();
|
||||
logUtils.log('ZrxTreasury.propose calldata:');
|
||||
logUtils.log(calldata);
|
||||
|
||||
const proposalId = await proposeTx.callAsync({ from: PROPOSER });
|
||||
const receipt = await proposeTx.awaitTransactionSuccessAsync({ from: PROPOSER });
|
||||
verifyEventsFromLogs(
|
||||
receipt.logs,
|
||||
[
|
||||
{
|
||||
...proposal,
|
||||
proposalId,
|
||||
executionEpoch,
|
||||
proposer: PROPOSER,
|
||||
operatedPoolIds: pools,
|
||||
},
|
||||
],
|
||||
ZrxTreasuryEvents.ProposalCreated,
|
||||
);
|
||||
await fastForwardToNextEpochAsync();
|
||||
await fastForwardToNextEpochAsync();
|
||||
await treasury
|
||||
.castVote(proposalId, true, VOTER_OPERATED_POOLS)
|
||||
.awaitTransactionSuccessAsync({ from: VOTER });
|
||||
await env.web3Wrapper.increaseTimeAsync(votingPeriod.plus(1).toNumber());
|
||||
await env.web3Wrapper.mineBlockAsync();
|
||||
const executeTx = await treasury.execute(proposalId, proposal.actions).awaitTransactionSuccessAsync();
|
||||
verifyEventsFromLogs(
|
||||
executeTx.logs,
|
||||
[
|
||||
{
|
||||
proposalId,
|
||||
},
|
||||
],
|
||||
ZrxTreasuryEvents.ProposalExecuted,
|
||||
);
|
||||
const recipient = '0xab66cc8fd10457ebc9d13b9760c835f0a4cbc487';
|
||||
verifyEventsFromLogs(
|
||||
executeTx.logs,
|
||||
[
|
||||
{
|
||||
_from: TREASURY_ADDRESS,
|
||||
_to: recipient,
|
||||
_value: new BigNumber(330_813).times('1e18'),
|
||||
},
|
||||
{
|
||||
_from: TREASURY_ADDRESS,
|
||||
_to: recipient,
|
||||
_value: new BigNumber(420000).times('1e18'),
|
||||
},
|
||||
],
|
||||
ERC20TokenEvents.Transfer,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1628225642,
|
||||
"version": "4.7.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.7.13",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.7.14 - _August 6, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.7.13 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.7.13",
|
||||
"version": "4.7.14",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,9 +52,9 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.3",
|
||||
|
@@ -3,10 +3,10 @@
|
||||
"version": "0.27.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Refactor Mixins which use WETH to also have an Internal variant, allowing WETH to be passed in for SwapRevertSampler",
|
||||
"pr": 245
|
||||
"note": "Add `Clipper` as a custom liquidity source"
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1628225642
|
||||
},
|
||||
{
|
||||
"version": "0.26.0",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.27.0 - _August 6, 2021_
|
||||
|
||||
* Add `Clipper` as a custom liquidity source
|
||||
|
||||
## v0.26.0 - _June 22, 2021_
|
||||
|
||||
* Add Lido stETH deposit integration (#260)
|
||||
|
@@ -25,7 +25,7 @@ import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinBalancer.sol";
|
||||
import "./mixins/MixinBalancerV2.sol";
|
||||
import "./mixins/MixinBancor.sol";
|
||||
import "./mixins/MixinBooster.sol";
|
||||
import "./mixins/MixinClipper.sol";
|
||||
import "./mixins/MixinCoFiX.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
@@ -51,7 +51,7 @@ contract BridgeAdapter is
|
||||
MixinBalancer,
|
||||
MixinBalancerV2,
|
||||
MixinBancor,
|
||||
MixinBooster,
|
||||
MixinClipper,
|
||||
MixinCoFiX,
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
@@ -77,7 +77,7 @@ contract BridgeAdapter is
|
||||
MixinBalancer()
|
||||
MixinBalancerV2()
|
||||
MixinBancor(weth)
|
||||
MixinBooster()
|
||||
MixinClipper(weth)
|
||||
MixinCoFiX()
|
||||
MixinCurve(weth)
|
||||
MixinCurveV2()
|
||||
@@ -248,8 +248,8 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.BOOSTER) {
|
||||
boughtAmount = _tradeBooster(
|
||||
} else if (protocolId == BridgeProtocols.CLIPPER) {
|
||||
boughtAmount = _tradeClipper(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
|
@@ -49,5 +49,5 @@ library BridgeProtocols {
|
||||
uint128 internal constant KYBERDMM = 19;
|
||||
uint128 internal constant CURVEV2 = 20;
|
||||
uint128 internal constant LIDO = 21;
|
||||
uint128 internal constant BOOSTER = 22;
|
||||
uint128 internal constant CLIPPER = 22;
|
||||
}
|
||||
|
@@ -39,13 +39,6 @@ interface IBancorNetwork {
|
||||
external
|
||||
payable
|
||||
returns (uint256);
|
||||
function conversionPath(address _sourceToken, address _targetToken) external view returns (address[] memory);
|
||||
function rateByPath(address[] memory _path, uint256 _amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
interface IBancorRegistry {
|
||||
function getAddress(bytes32 _contractName) external view returns (address);
|
||||
function BANCOR_NETWORK() external view returns (bytes32);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,18 +62,6 @@ contract MixinBancor {
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
return _tradeBancorInternal(WETH, buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
function _tradeBancorInternal(
|
||||
IEtherTokenV06 weth,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
IBancorNetwork bancorNetworkAddress;
|
||||
@@ -98,7 +79,7 @@ contract MixinBancor {
|
||||
require(path.length >= 2, "MixinBancor/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(
|
||||
path[path.length - 1] == buyToken ||
|
||||
(path[path.length - 1] == BANCOR_ETH_ADDRESS && buyToken == weth),
|
||||
(path[path.length - 1] == BANCOR_ETH_ADDRESS && buyToken == WETH),
|
||||
"MixinBancor/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
|
||||
);
|
||||
|
||||
@@ -107,7 +88,7 @@ contract MixinBancor {
|
||||
// The Bancor path will have ETH as the 0xeee address
|
||||
// Bancor expects to be paid in ETH not WETH
|
||||
if (path[0] == BANCOR_ETH_ADDRESS) {
|
||||
weth.withdraw(sellAmount);
|
||||
WETH.withdraw(sellAmount);
|
||||
payableAmount = sellAmount;
|
||||
} else {
|
||||
// Grant an allowance to the Bancor Network.
|
||||
@@ -128,7 +109,7 @@ contract MixinBancor {
|
||||
0 // affiliateFee; no fee paid
|
||||
);
|
||||
if (path[path.length - 1] == BANCOR_ETH_ADDRESS) {
|
||||
weth.deposit{value: boughtAmount}();
|
||||
WETH.deposit{value: boughtAmount}();
|
||||
}
|
||||
|
||||
return boughtAmount;
|
||||
|
@@ -1,68 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "../IBridgeAdapter.sol";
|
||||
|
||||
|
||||
interface IBooster {
|
||||
function swap(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
address recipient
|
||||
)
|
||||
external
|
||||
returns (uint256);
|
||||
}
|
||||
|
||||
contract MixinBooster {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeBooster(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(IBooster pool) = abi.decode(bridgeData, (IBooster));
|
||||
// Grant the pool an allowance.
|
||||
sellToken.approveIfBelow(address(pool), sellAmount);
|
||||
|
||||
// Convert the tokens
|
||||
boughtAmount = pool.swap(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
address(this)
|
||||
);
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -0,0 +1,148 @@
|
||||
// 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 "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "../IBridgeAdapter.sol";
|
||||
import "../../../vendor/ILiquidityProvider.sol";
|
||||
|
||||
contract MixinClipper {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
{
|
||||
WETH = weth;
|
||||
}
|
||||
|
||||
function _tradeClipper(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// We can only use ETH with Clipper, no WETH available
|
||||
(ILiquidityProvider clipper, bytes memory auxiliaryData) =
|
||||
abi.decode(bridgeData, (ILiquidityProvider, bytes));
|
||||
|
||||
if (sellToken == WETH) {
|
||||
boughtAmount = _executeSellEthForToken(
|
||||
clipper,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
} else if (buyToken == WETH) {
|
||||
boughtAmount = _executeSellTokenForEth(
|
||||
clipper,
|
||||
sellToken,
|
||||
sellAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _executeSellTokenForToken(
|
||||
clipper,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
|
||||
function _executeSellEthForToken(
|
||||
ILiquidityProvider clipper,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory auxiliaryData
|
||||
)
|
||||
private
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Clipper requires ETH and doesn't support WETH
|
||||
WETH.withdraw(sellAmount);
|
||||
boughtAmount = clipper.sellEthForToken{ value: sellAmount }(
|
||||
buyToken,
|
||||
address(this),
|
||||
1,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
|
||||
function _executeSellTokenForEth(
|
||||
ILiquidityProvider clipper,
|
||||
IERC20TokenV06 sellToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory auxiliaryData
|
||||
)
|
||||
private
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Optimization: We can transfer the tokens into clipper rather than
|
||||
// have an allowance updated
|
||||
sellToken.compatTransfer(address(clipper), sellAmount);
|
||||
|
||||
boughtAmount = clipper.sellTokenForEth(
|
||||
sellToken,
|
||||
payable(address(this)),
|
||||
1,
|
||||
auxiliaryData
|
||||
);
|
||||
|
||||
// we want WETH for possible future trades
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
}
|
||||
|
||||
function _executeSellTokenForToken(
|
||||
ILiquidityProvider clipper,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory auxiliaryData
|
||||
)
|
||||
private
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Optimization: We can transfer the tokens into clipper rather than
|
||||
// have an allowance updated
|
||||
sellToken.compatTransfer(address(clipper), sellAmount);
|
||||
|
||||
boughtAmount = clipper.sellTokenForToken(
|
||||
sellToken,
|
||||
buyToken,
|
||||
address(this),
|
||||
1,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
}
|
@@ -57,26 +57,13 @@ contract MixinCurve {
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
return _tradeCurveInternal(WETH, sellToken, buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
function _tradeCurveInternal(
|
||||
IEtherTokenV06 weth,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data to get the Curve metadata.
|
||||
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
|
||||
uint256 payableAmount;
|
||||
if (sellToken == weth) {
|
||||
if (sellToken == WETH) {
|
||||
payableAmount = sellAmount;
|
||||
weth.withdraw(sellAmount);
|
||||
WETH.withdraw(sellAmount);
|
||||
} else {
|
||||
sellToken.approveIfBelow(data.curveAddress, sellAmount);
|
||||
}
|
||||
@@ -96,9 +83,9 @@ contract MixinCurve {
|
||||
resultData.rrevert();
|
||||
}
|
||||
|
||||
if (buyToken == weth) {
|
||||
if (buyToken == WETH) {
|
||||
boughtAmount = address(this).balance;
|
||||
weth.deposit{ value: boughtAmount }();
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
}
|
||||
|
||||
return buyToken.balanceOf(address(this)).safeSub(beforeBalance);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@@ -52,7 +52,6 @@ interface IKyberNetworkProxy {
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount);
|
||||
|
||||
}
|
||||
|
||||
contract MixinKyber {
|
||||
@@ -79,26 +78,12 @@ contract MixinKyber {
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
return _tradeKyberInternal(KYBER_ETH_ADDRESS, WETH, sellToken, buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
function _tradeKyberInternal(
|
||||
IERC20TokenV06 kyberEthAddress,
|
||||
IEtherTokenV06 weth,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(IKyberNetworkProxy kyber, bytes memory hint) =
|
||||
abi.decode(bridgeData, (IKyberNetworkProxy, bytes));
|
||||
|
||||
uint256 payableAmount = 0;
|
||||
if (sellToken != weth) {
|
||||
if (sellToken != WETH) {
|
||||
// If the input token is not WETH, grant an allowance to the exchange
|
||||
// to spend them.
|
||||
sellToken.approveIfBelow(
|
||||
@@ -108,18 +93,18 @@ contract MixinKyber {
|
||||
} else {
|
||||
// If the input token is WETH, unwrap it and attach it to the call.
|
||||
payableAmount = sellAmount;
|
||||
weth.withdraw(payableAmount);
|
||||
WETH.withdraw(payableAmount);
|
||||
}
|
||||
|
||||
// Try to sell all of this contract's input token balance through
|
||||
// `KyberNetworkProxy.trade()`.
|
||||
boughtAmount = kyber.tradeWithHint{ value: payableAmount }(
|
||||
// Input token.
|
||||
sellToken == weth ? kyberEthAddress : sellToken,
|
||||
sellToken == WETH ? KYBER_ETH_ADDRESS : sellToken,
|
||||
// Sell amount.
|
||||
sellAmount,
|
||||
// Output token.
|
||||
buyToken == weth ? kyberEthAddress : buyToken,
|
||||
buyToken == WETH ? KYBER_ETH_ADDRESS : buyToken,
|
||||
// Transfer to this contract
|
||||
address(uint160(address(this))),
|
||||
// Buy as much as possible.
|
||||
@@ -131,8 +116,8 @@ contract MixinKyber {
|
||||
hint
|
||||
);
|
||||
// If receving ETH, wrap it to WETH.
|
||||
if (buyToken == weth) {
|
||||
weth.deposit{ value: boughtAmount }();
|
||||
if (buyToken == WETH) {
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
}
|
||||
return boughtAmount;
|
||||
}
|
||||
|
@@ -30,8 +30,6 @@ import "../IBridgeAdapter.sol";
|
||||
*/
|
||||
interface IKyberDmmRouter {
|
||||
|
||||
function factory() external view returns (address);
|
||||
|
||||
/// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
|
||||
/// The first element of path is the input token, the last is the output token, and any intermediate elements represent
|
||||
/// intermediate pairs to trade through (if, for example, a direct pair does not exist).
|
||||
|
@@ -58,23 +58,10 @@ contract MixinLido {
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
return _tradeLidoInternal(WETH, sellToken, buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
function _tradeLidoInternal(
|
||||
IEtherTokenV06 weth,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(ILido lido) = abi.decode(bridgeData, (ILido));
|
||||
if (address(sellToken) == address(weth) && address(buyToken) == address(lido)) {
|
||||
weth.withdraw(sellAmount);
|
||||
if (address(sellToken) == address(WETH) && address(buyToken) == address(lido)) {
|
||||
WETH.withdraw(sellAmount);
|
||||
boughtAmount = lido.getPooledEthByShares(lido.submit{ value: sellAmount}(address(0)));
|
||||
} else {
|
||||
revert("MixinLido/UNSUPPORTED_TOKEN_PAIR");
|
||||
|
@@ -66,26 +66,12 @@ contract MixinMooniswap {
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
|
||||
return _tradeMooniswapInternal(WETH, sellToken, buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
function _tradeMooniswapInternal(
|
||||
IEtherTokenV06 weth,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(IMooniswapPool pool) = abi.decode(bridgeData, (IMooniswapPool));
|
||||
|
||||
// Convert WETH to ETH.
|
||||
uint256 ethValue = 0;
|
||||
if (sellToken == weth) {
|
||||
weth.withdraw(sellAmount);
|
||||
if (sellToken == WETH) {
|
||||
WETH.withdraw(sellAmount);
|
||||
ethValue = sellAmount;
|
||||
} else {
|
||||
// Grant the pool an allowance.
|
||||
@@ -96,16 +82,16 @@ contract MixinMooniswap {
|
||||
}
|
||||
|
||||
boughtAmount = pool.swap{value: ethValue}(
|
||||
sellToken == weth ? IERC20TokenV06(0) : sellToken,
|
||||
buyToken == weth ? IERC20TokenV06(0) : buyToken,
|
||||
sellToken == WETH ? IERC20TokenV06(0) : sellToken,
|
||||
buyToken == WETH ? IERC20TokenV06(0) : buyToken,
|
||||
sellAmount,
|
||||
1,
|
||||
address(0)
|
||||
);
|
||||
|
||||
// Wrap ETH to WETH.
|
||||
if (buyToken == weth) {
|
||||
weth.deposit{value:boughtAmount}();
|
||||
if (buyToken == WETH) {
|
||||
WETH.deposit{value:boughtAmount}();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -124,35 +124,21 @@ contract MixinUniswap {
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
return _tradeUniswapInternal(WETH, sellToken, buyToken, sellAmount, bridgeData);
|
||||
}
|
||||
|
||||
function _tradeUniswapInternal(
|
||||
IEtherTokenV06 weth,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
IUniswapExchangeFactory exchangeFactory =
|
||||
abi.decode(bridgeData, (IUniswapExchangeFactory));
|
||||
|
||||
// Get the exchange for the token pair.
|
||||
IUniswapExchange exchange = _getUniswapExchangeForTokenPair(
|
||||
weth,
|
||||
exchangeFactory,
|
||||
sellToken,
|
||||
buyToken
|
||||
);
|
||||
|
||||
// Convert from WETH to a token.
|
||||
if (sellToken == weth) {
|
||||
if (sellToken == WETH) {
|
||||
// Unwrap the WETH.
|
||||
weth.withdraw(sellAmount);
|
||||
WETH.withdraw(sellAmount);
|
||||
// Buy as much of `buyToken` token with ETH as possible
|
||||
boughtAmount = exchange.ethToTokenTransferInput{ value: sellAmount }(
|
||||
// Minimum buy amount.
|
||||
@@ -164,7 +150,7 @@ contract MixinUniswap {
|
||||
);
|
||||
|
||||
// Convert from a token to WETH.
|
||||
} else if (buyToken == weth) {
|
||||
} else if (buyToken == WETH) {
|
||||
// Grant the exchange an allowance.
|
||||
sellToken.approveIfBelow(
|
||||
address(exchange),
|
||||
@@ -180,7 +166,7 @@ contract MixinUniswap {
|
||||
block.timestamp
|
||||
);
|
||||
// Wrap the ETH.
|
||||
weth.deposit{ value: boughtAmount }();
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
// Convert from one token to another.
|
||||
} else {
|
||||
// Grant the exchange an allowance.
|
||||
@@ -214,7 +200,6 @@ contract MixinUniswap {
|
||||
/// @param buyToken The address of the token we are converting to.
|
||||
/// @return exchange The uniswap exchange.
|
||||
function _getUniswapExchangeForTokenPair(
|
||||
IEtherTokenV06 weth,
|
||||
IUniswapExchangeFactory exchangeFactory,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken
|
||||
@@ -224,7 +209,7 @@ contract MixinUniswap {
|
||||
returns (IUniswapExchange exchange)
|
||||
{
|
||||
// Whichever isn't WETH is the exchange token.
|
||||
exchange = sellToken == weth
|
||||
exchange = sellToken == WETH
|
||||
? exchangeFactory.getExchange(buyToken)
|
||||
: exchangeFactory.getExchange(sellToken);
|
||||
require(address(exchange) != address(0), "MixinUniswap/NO_EXCHANGE");
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-zero-ex",
|
||||
"version": "0.26.0",
|
||||
"version": "0.27.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -43,7 +43,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinBooster|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinClipper|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|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.6.0",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contract-addresses": "^6.5.0",
|
||||
"@0x/contracts-erc20": "^3.3.14",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-test-utils": "^5.4.6",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/order-utils": "^10.4.27",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
@@ -83,7 +83,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/protocol-utils": "^1.7.2",
|
||||
"@0x/protocol-utils": "^1.8.0",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
@@ -82,7 +82,7 @@ import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransa
|
||||
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
|
||||
import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json';
|
||||
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
|
||||
import * as MixinBooster from '../test/generated-artifacts/MixinBooster.json';
|
||||
import * as MixinClipper from '../test/generated-artifacts/MixinClipper.json';
|
||||
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';
|
||||
@@ -258,7 +258,7 @@ export const artifacts = {
|
||||
MixinBalancer: MixinBalancer as ContractArtifact,
|
||||
MixinBalancerV2: MixinBalancerV2 as ContractArtifact,
|
||||
MixinBancor: MixinBancor as ContractArtifact,
|
||||
MixinBooster: MixinBooster as ContractArtifact,
|
||||
MixinClipper: MixinClipper as ContractArtifact,
|
||||
MixinCoFiX: MixinCoFiX as ContractArtifact,
|
||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
|
@@ -80,7 +80,7 @@ export * from '../test/generated-wrappers/meta_transactions_feature';
|
||||
export * from '../test/generated-wrappers/mixin_balancer';
|
||||
export * from '../test/generated-wrappers/mixin_balancer_v2';
|
||||
export * from '../test/generated-wrappers/mixin_bancor';
|
||||
export * from '../test/generated-wrappers/mixin_booster';
|
||||
export * from '../test/generated-wrappers/mixin_clipper';
|
||||
export * from '../test/generated-wrappers/mixin_co_fi_x';
|
||||
export * from '../test/generated-wrappers/mixin_crypto_com';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
|
@@ -113,7 +113,7 @@
|
||||
"test/generated-artifacts/MixinBalancer.json",
|
||||
"test/generated-artifacts/MixinBalancerV2.json",
|
||||
"test/generated-artifacts/MixinBancor.json",
|
||||
"test/generated-artifacts/MixinBooster.json",
|
||||
"test/generated-artifacts/MixinClipper.json",
|
||||
"test/generated-artifacts/MixinCoFiX.json",
|
||||
"test/generated-artifacts/MixinCryptoCom.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
|
@@ -1,12 +1,96 @@
|
||||
[
|
||||
{
|
||||
"version": "7.0.0",
|
||||
"version": "16.24.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "SwapRevertSampler. Refactored sampler to use exchange functions. Remove gas schedule.",
|
||||
"pr": 245
|
||||
"note": "Add `Clipper` as a custom liquidity source",
|
||||
"pr": 299
|
||||
},
|
||||
{
|
||||
"note": "Added `Curve` `Tricrypto2` and `ESD` v2",
|
||||
"pr": 302
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1628225642
|
||||
},
|
||||
{
|
||||
"version": "16.23.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix fill amount rounding error when covnerting fills to orders.",
|
||||
"pr": 296
|
||||
}
|
||||
],
|
||||
"timestamp": 1627572227
|
||||
},
|
||||
{
|
||||
"version": "16.23.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "ACryptoS",
|
||||
"pr": 284
|
||||
}
|
||||
],
|
||||
"timestamp": 1626473497
|
||||
},
|
||||
{
|
||||
"version": "16.22.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "IronSwap",
|
||||
"pr": 281
|
||||
}
|
||||
],
|
||||
"timestamp": 1626214787
|
||||
},
|
||||
{
|
||||
"version": "16.21.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "JetSwap",
|
||||
"pr": 280
|
||||
}
|
||||
],
|
||||
"timestamp": 1625904026
|
||||
},
|
||||
{
|
||||
"version": "16.20.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "ShibaSwap",
|
||||
"pr": 276
|
||||
}
|
||||
],
|
||||
"timestamp": 1625607277
|
||||
},
|
||||
{
|
||||
"version": "16.19.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix LiquidityProvider fallback",
|
||||
"pr": 272
|
||||
}
|
||||
],
|
||||
"timestamp": 1625544188
|
||||
},
|
||||
{
|
||||
"version": "16.19.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add LiquidityProvider to Polygon sources",
|
||||
"pr": 270
|
||||
}
|
||||
],
|
||||
"timestamp": 1625190486
|
||||
},
|
||||
{
|
||||
"version": "6.18.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Polygon Balance V2"
|
||||
}
|
||||
],
|
||||
"timestamp": 1624987208
|
||||
},
|
||||
{
|
||||
"timestamp": 1624562704,
|
||||
|
@@ -5,6 +5,43 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v16.24.0 - _August 6, 2021_
|
||||
|
||||
* Add `Clipper` as a custom liquidity source (#299)
|
||||
* Added `Curve` `Tricrypto2` and `ESD` v2 (#302)
|
||||
|
||||
## v16.23.1 - _July 29, 2021_
|
||||
|
||||
* Fix fill amount rounding error when covnerting fills to orders. (#296)
|
||||
|
||||
## v16.23.0 - _July 16, 2021_
|
||||
|
||||
* ACryptoS (#284)
|
||||
|
||||
## v16.22.0 - _July 13, 2021_
|
||||
|
||||
* IronSwap (#281)
|
||||
|
||||
## v16.21.0 - _July 10, 2021_
|
||||
|
||||
* JetSwap (#280)
|
||||
|
||||
## v16.20.0 - _July 6, 2021_
|
||||
|
||||
* ShibaSwap (#276)
|
||||
|
||||
## v16.19.1 - _July 6, 2021_
|
||||
|
||||
* Fix LiquidityProvider fallback (#272)
|
||||
|
||||
## v16.19.0 - _July 2, 2021_
|
||||
|
||||
* Add LiquidityProvider to Polygon sources (#270)
|
||||
|
||||
## v6.18.3 - _June 29, 2021_
|
||||
|
||||
* Polygon Balance V2
|
||||
|
||||
## v6.18.2 - _June 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
144
packages/asset-swapper/contracts/src/ApproximateBuys.sol
Normal file
144
packages/asset-swapper/contracts/src/ApproximateBuys.sol
Normal file
@@ -0,0 +1,144 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
|
||||
|
||||
|
||||
contract ApproximateBuys {
|
||||
|
||||
/// @dev Information computing buy quotes for sources that do not have native
|
||||
/// buy quote support.
|
||||
struct ApproximateBuyQuoteOpts {
|
||||
// Arbitrary maker token data to pass to `getSellQuoteCallback`.
|
||||
bytes makerTokenData;
|
||||
// Arbitrary taker token data to pass to `getSellQuoteCallback`.
|
||||
bytes takerTokenData;
|
||||
// Callback to retrieve a sell quote.
|
||||
function (bytes memory, bytes memory, uint256)
|
||||
internal
|
||||
view
|
||||
returns (uint256) getSellQuoteCallback;
|
||||
}
|
||||
|
||||
uint256 private constant ONE_HUNDED_PERCENT_BPS = 1e4;
|
||||
/// @dev Maximum approximate (positive) error rate when approximating a buy quote.
|
||||
uint256 private constant APPROXIMATE_BUY_TARGET_EPSILON_BPS = 0.0005e4;
|
||||
/// @dev Maximum iterations to perform when approximating a buy quote.
|
||||
uint256 private constant APPROXIMATE_BUY_MAX_ITERATIONS = 5;
|
||||
|
||||
function _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts memory opts,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
takerTokenAmounts = new uint256[](makerTokenAmounts.length);
|
||||
if (makerTokenAmounts.length == 0) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
uint256 sellAmount = opts.getSellQuoteCallback(
|
||||
opts.makerTokenData,
|
||||
opts.takerTokenData,
|
||||
makerTokenAmounts[0]
|
||||
);
|
||||
if (sellAmount == 0) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
uint256 buyAmount = opts.getSellQuoteCallback(
|
||||
opts.takerTokenData,
|
||||
opts.makerTokenData,
|
||||
sellAmount
|
||||
);
|
||||
if (buyAmount == 0) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < makerTokenAmounts.length; i++) {
|
||||
for (uint256 iter = 0; iter < APPROXIMATE_BUY_MAX_ITERATIONS; iter++) {
|
||||
// adjustedSellAmount = previousSellAmount * (target/actual) * JUMP_MULTIPLIER
|
||||
sellAmount = _safeGetPartialAmountCeil(
|
||||
makerTokenAmounts[i],
|
||||
buyAmount,
|
||||
sellAmount
|
||||
);
|
||||
if (sellAmount == 0) {
|
||||
break;
|
||||
}
|
||||
sellAmount = _safeGetPartialAmountCeil(
|
||||
(ONE_HUNDED_PERCENT_BPS + APPROXIMATE_BUY_TARGET_EPSILON_BPS),
|
||||
ONE_HUNDED_PERCENT_BPS,
|
||||
sellAmount
|
||||
);
|
||||
if (sellAmount == 0) {
|
||||
break;
|
||||
}
|
||||
uint256 _buyAmount = opts.getSellQuoteCallback(
|
||||
opts.takerTokenData,
|
||||
opts.makerTokenData,
|
||||
sellAmount
|
||||
);
|
||||
if (_buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
// We re-use buyAmount next iteration, only assign if it is
|
||||
// non zero
|
||||
buyAmount = _buyAmount;
|
||||
// If we've reached our goal, exit early
|
||||
if (buyAmount >= makerTokenAmounts[i]) {
|
||||
uint256 eps =
|
||||
(buyAmount - makerTokenAmounts[i]) * ONE_HUNDED_PERCENT_BPS /
|
||||
makerTokenAmounts[i];
|
||||
if (eps <= APPROXIMATE_BUY_TARGET_EPSILON_BPS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We do our best to close in on the requested amount, but we can either over buy or under buy and exit
|
||||
// if we hit a max iteration limit
|
||||
// We scale the sell amount to get the approximate target
|
||||
takerTokenAmounts[i] = _safeGetPartialAmountCeil(
|
||||
makerTokenAmounts[i],
|
||||
buyAmount,
|
||||
sellAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function _safeGetPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
if (numerator == 0 || target == 0 || denominator == 0) return 0;
|
||||
uint256 c = numerator * target;
|
||||
if (c / numerator != target) return 0;
|
||||
return (c + (denominator - 1)) / denominator;
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,29 +20,26 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinBalancer.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./interfaces/IBalancer.sol";
|
||||
|
||||
contract BalancerSampler is
|
||||
MixinBalancer,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
function sampleSwapFromBalancer(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeBalancer(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
contract BalancerSampler {
|
||||
|
||||
/// @dev Base gas limit for Balancer calls.
|
||||
uint256 constant private BALANCER_CALL_GAS = 300e3; // 300k
|
||||
|
||||
// Balancer math constants
|
||||
// https://github.com/balancer-labs/balancer-core/blob/master/contracts/BConst.sol
|
||||
uint256 constant private BONE = 10 ** 18;
|
||||
uint256 constant private MAX_IN_RATIO = BONE / 2;
|
||||
uint256 constant private MAX_OUT_RATIO = (BONE / 3) + 1 wei;
|
||||
|
||||
struct BalancerState {
|
||||
uint256 takerTokenBalance;
|
||||
uint256 makerTokenBalance;
|
||||
uint256 takerTokenWeight;
|
||||
uint256 makerTokenWeight;
|
||||
uint256 swapFee;
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Balancer.
|
||||
@@ -50,7 +47,6 @@ contract BalancerSampler is
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromBalancer(
|
||||
@@ -60,17 +56,52 @@ contract BalancerSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(poolAddress),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancer
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
IBalancer pool = IBalancer(poolAddress);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
if (!pool.isBound(takerToken) || !pool.isBound(makerToken)) {
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
BalancerState memory poolState;
|
||||
poolState.takerTokenBalance = pool.getBalance(takerToken);
|
||||
poolState.makerTokenBalance = pool.getBalance(makerToken);
|
||||
poolState.takerTokenWeight = pool.getDenormalizedWeight(takerToken);
|
||||
poolState.makerTokenWeight = pool.getDenormalizedWeight(makerToken);
|
||||
poolState.swapFee = pool.getSwapFee();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
// Handles this revert scenario:
|
||||
// https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol#L443
|
||||
if (takerTokenAmounts[i] > _bmul(poolState.takerTokenBalance, MAX_IN_RATIO)) {
|
||||
break;
|
||||
}
|
||||
try
|
||||
pool.calcOutGivenIn
|
||||
{gas: BALANCER_CALL_GAS}
|
||||
(
|
||||
poolState.takerTokenBalance,
|
||||
poolState.takerTokenWeight,
|
||||
poolState.makerTokenBalance,
|
||||
poolState.makerTokenWeight,
|
||||
takerTokenAmounts[i],
|
||||
poolState.swapFee
|
||||
)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Balancer.
|
||||
@@ -78,7 +109,6 @@ contract BalancerSampler is
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromBalancer(
|
||||
@@ -88,18 +118,74 @@ contract BalancerSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(poolAddress),
|
||||
buyTokenData: abi.encode(poolAddress),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancer
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
IBalancer pool = IBalancer(poolAddress);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
if (!pool.isBound(takerToken) || !pool.isBound(makerToken)) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
BalancerState memory poolState;
|
||||
poolState.takerTokenBalance = pool.getBalance(takerToken);
|
||||
poolState.makerTokenBalance = pool.getBalance(makerToken);
|
||||
poolState.takerTokenWeight = pool.getDenormalizedWeight(takerToken);
|
||||
poolState.makerTokenWeight = pool.getDenormalizedWeight(makerToken);
|
||||
poolState.swapFee = pool.getSwapFee();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
// Handles this revert scenario:
|
||||
// https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol#L505
|
||||
if (makerTokenAmounts[i] > _bmul(poolState.makerTokenBalance, MAX_OUT_RATIO)) {
|
||||
break;
|
||||
}
|
||||
try
|
||||
pool.calcInGivenOut
|
||||
{gas: BALANCER_CALL_GAS}
|
||||
(
|
||||
poolState.takerTokenBalance,
|
||||
poolState.takerTokenWeight,
|
||||
poolState.makerTokenBalance,
|
||||
poolState.makerTokenWeight,
|
||||
makerTokenAmounts[i],
|
||||
poolState.swapFee
|
||||
)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
takerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (takerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Hacked version of Balancer's `bmul` function, returning 0 instead
|
||||
/// of reverting.
|
||||
/// https://github.com/balancer-labs/balancer-core/blob/master/contracts/BNum.sol#L63-L73
|
||||
/// @param a The first operand.
|
||||
/// @param b The second operand.
|
||||
/// @param c The result of the multiplication, or 0 if `bmul` would've reverted.
|
||||
function _bmul(uint256 a, uint256 b)
|
||||
private
|
||||
pure
|
||||
returns (uint256 c)
|
||||
{
|
||||
uint c0 = a * b;
|
||||
if (a != 0 && c0 / a != b) {
|
||||
return 0;
|
||||
}
|
||||
uint c1 = c0 + (BONE / 2);
|
||||
if (c1 < c0) {
|
||||
return 0;
|
||||
}
|
||||
uint c2 = c1 / BONE;
|
||||
return c2;
|
||||
}
|
||||
}
|
||||
|
@@ -20,29 +20,44 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinBalancerV2.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
contract BalancerV2Sampler is
|
||||
MixinBalancerV2,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Minimal Balancer V2 Vault interface
|
||||
/// for documentation refer to https://github.com/balancer-labs/balancer-core-v2/blob/master/contracts/vault/interfaces/IVault.sol
|
||||
interface IBalancerV2Vault {
|
||||
enum SwapKind { GIVEN_IN, GIVEN_OUT }
|
||||
|
||||
function sampleSwapFromBalancerV2(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeBalancerV2(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
struct BatchSwapStep {
|
||||
bytes32 poolId;
|
||||
uint256 assetInIndex;
|
||||
uint256 assetOutIndex;
|
||||
uint256 amount;
|
||||
bytes userData;
|
||||
}
|
||||
|
||||
struct FundManagement {
|
||||
address sender;
|
||||
bool fromInternalBalance;
|
||||
address payable recipient;
|
||||
bool toInternalBalance;
|
||||
}
|
||||
|
||||
function queryBatchSwap(
|
||||
SwapKind kind,
|
||||
BatchSwapStep[] calldata swaps,
|
||||
IAsset[] calldata assets,
|
||||
FundManagement calldata funds
|
||||
) external returns (int256[] memory assetDeltas);
|
||||
}
|
||||
interface IAsset {
|
||||
// solhint-disable-previous-line no-empty-blocks
|
||||
}
|
||||
|
||||
contract BalancerV2Sampler is SamplerUtils {
|
||||
|
||||
struct BalancerV2PoolInfo {
|
||||
bytes32 poolId;
|
||||
address vault;
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Balancer V2.
|
||||
@@ -50,27 +65,48 @@ contract BalancerV2Sampler is
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromBalancerV2(
|
||||
BalancerV2BridgeData memory poolInfo,
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(poolInfo),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancerV2
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||
IAsset[] memory swapAssets = new IAsset[](2);
|
||||
swapAssets[0] = IAsset(takerToken);
|
||||
swapAssets[1] = IAsset(makerToken);
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||
_createSwapFunds();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||
_createSwapSteps(poolInfo, takerTokenAmounts[i]);
|
||||
|
||||
try
|
||||
// For sells we specify the takerToken which is what the vault will receive from the trade
|
||||
vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_IN, swapSteps, swapAssets, swapFunds)
|
||||
// amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
|
||||
returns (int256[] memory amounts) {
|
||||
// Outgoing balance is negative so we need to flip the sign
|
||||
int256 amountOutFromPool = amounts[1] * -1;
|
||||
if (amountOutFromPool <= 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = uint256(amountOutFromPool);
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Balancer V2.
|
||||
@@ -78,27 +114,76 @@ contract BalancerV2Sampler is
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromBalancerV2(
|
||||
BalancerV2BridgeData memory poolInfo,
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(poolInfo),
|
||||
buyTokenData: abi.encode(poolInfo),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancerV2
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||
IAsset[] memory swapAssets = new IAsset[](2);
|
||||
swapAssets[0] = IAsset(takerToken);
|
||||
swapAssets[1] = IAsset(makerToken);
|
||||
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||
_createSwapFunds();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||
_createSwapSteps(poolInfo, makerTokenAmounts[i]);
|
||||
|
||||
try
|
||||
// For buys we specify the makerToken which is what taker will receive from the trade
|
||||
vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_OUT, swapSteps, swapAssets, swapFunds)
|
||||
returns (int256[] memory amounts) {
|
||||
int256 amountIntoPool = amounts[0];
|
||||
if (amountIntoPool <= 0) {
|
||||
break;
|
||||
}
|
||||
takerTokenAmounts[i] = uint256(amountIntoPool);
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _createSwapSteps(
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
uint256 amount
|
||||
) private pure returns (IBalancerV2Vault.BatchSwapStep[] memory) {
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||
new IBalancerV2Vault.BatchSwapStep[](1);
|
||||
swapSteps[0] = IBalancerV2Vault.BatchSwapStep({
|
||||
poolId: poolInfo.poolId,
|
||||
assetInIndex: 0,
|
||||
assetOutIndex: 1,
|
||||
amount: amount,
|
||||
userData: ""
|
||||
});
|
||||
|
||||
return swapSteps;
|
||||
}
|
||||
|
||||
function _createSwapFunds()
|
||||
private
|
||||
view
|
||||
returns (IBalancerV2Vault.FundManagement memory)
|
||||
{
|
||||
return
|
||||
IBalancerV2Vault.FundManagement({
|
||||
sender: address(this),
|
||||
fromInternalBalance: false,
|
||||
recipient: payable(address(this)),
|
||||
toInternalBalance: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,21 +20,11 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinBancor.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./interfaces/IBancor.sol";
|
||||
|
||||
contract CompilerHack {}
|
||||
|
||||
contract BancorSampler is
|
||||
CompilerHack,
|
||||
MixinBancor,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinBancor(weth)
|
||||
{ }
|
||||
contract BancorSampler is CompilerHack {
|
||||
|
||||
/// @dev Base gas limit for Bancor calls.
|
||||
uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k
|
||||
@@ -44,23 +34,6 @@ contract BancorSampler is
|
||||
address[][] paths;
|
||||
}
|
||||
|
||||
function sampleSwapFromBancor(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeBancorInternal(
|
||||
_getNativeWrappedToken(),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Bancor.
|
||||
/// @param opts BancorSamplerOpts The Bancor registry contract address and paths
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
@@ -68,7 +41,6 @@ contract BancorSampler is
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return bancorNetwork the Bancor Network address
|
||||
/// @return path the selected conversion path from bancor
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromBancor(
|
||||
@@ -78,30 +50,34 @@ contract BancorSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
address bancorNetwork,
|
||||
address[] memory path,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
view
|
||||
returns (address bancorNetwork, address[] memory path, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
if (opts.paths.length == 0) {
|
||||
return (bancorNetwork, path, gasUsed, makerTokenAmounts);
|
||||
return (bancorNetwork, path, makerTokenAmounts);
|
||||
}
|
||||
|
||||
(bancorNetwork, path) = _findBestPath(opts, takerToken, makerToken, takerTokenAmounts);
|
||||
makerTokenAmounts = new uint256[](takerTokenAmounts.length);
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(bancorNetwork, path),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBancor
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
|
||||
return (bancorNetwork, path, gasUsed, makerTokenAmounts);
|
||||
for (uint256 i = 0; i < makerTokenAmounts.length; i++) {
|
||||
try
|
||||
IBancorNetwork(bancorNetwork)
|
||||
.rateByPath
|
||||
{gas: BANCOR_CALL_GAS}
|
||||
(path, takerTokenAmounts[i])
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (bancorNetwork, path, makerTokenAmounts);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Bancor. Unimplemented
|
||||
@@ -111,7 +87,6 @@ contract BancorSampler is
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return bancorNetwork the Bancor Network address
|
||||
/// @return path the selected conversion path from bancor
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromBancor(
|
||||
@@ -122,7 +97,7 @@ contract BancorSampler is
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (address bancorNetwork, address[] memory path, uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
returns (address bancorNetwork, address[] memory path, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -1,104 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinBooster.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
contract BoosterSampler is
|
||||
MixinBooster,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
function sampleSwapFromBooster(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeBooster(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Booster.
|
||||
/// @param pool Address of the Booster Pool.
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromBooster(
|
||||
address pool,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBooster
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Booster.
|
||||
/// @param pool Address of the Booster pool.
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromBooster(
|
||||
address pool,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(pool),
|
||||
buyTokenData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBooster
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,99 +20,142 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinCurve.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./interfaces/ICurve.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract CurveSampler is
|
||||
MixinCurve,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinCurve(weth)
|
||||
{ }
|
||||
|
||||
function sampleSwapFromCurve(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeCurveInternal(
|
||||
_getNativeWrappedToken(),
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
/// @dev Information for sampling from curve sources.
|
||||
struct CurveInfo {
|
||||
address poolAddress;
|
||||
bytes4 sellQuoteFunctionSelector;
|
||||
bytes4 buyQuoteFunctionSelector;
|
||||
}
|
||||
|
||||
/// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
|
||||
/// So a reasonable ceil is 150k per token. Biggest Curve has 4 tokens.
|
||||
uint256 constant private CURVE_CALL_GAS = 2000e3; // Was 600k for Curve but SnowSwap is using 1500k+
|
||||
|
||||
/// @dev Sample sell quotes from Curve.
|
||||
/// @param curveInfo Curve information specific to this token pair.
|
||||
/// @param takerToken The taker token to sell.
|
||||
/// @param makerToken The maker token to buy.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromCurve(
|
||||
CurveBridgeData memory curveInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
CurveInfo memory curveInfo,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(curveInfo),
|
||||
getSwapQuoteCallback: this.sampleSwapFromCurve
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
curveInfo.poolAddress.staticcall.gas(CURVE_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
curveInfo.sellQuoteFunctionSelector,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Curve.
|
||||
/// @param curveInfo Curve information specific to this token pair.
|
||||
/// @param takerToken The taker token to sell.
|
||||
/// @param makerToken The maker token to buy.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromCurve(
|
||||
CurveBridgeData memory curveInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
CurveInfo memory curveInfo,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(curveInfo),
|
||||
buyTokenData: abi.encode(
|
||||
CurveBridgeData({
|
||||
curveAddress: curveInfo.curveAddress,
|
||||
exchangeFunctionSelector: curveInfo.exchangeFunctionSelector,
|
||||
fromCoinIdx: curveInfo.toCoinIdx,
|
||||
toCoinIdx: curveInfo.fromCoinIdx
|
||||
})
|
||||
),
|
||||
getSwapQuoteCallback: this.sampleSwapFromCurve
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
if (curveInfo.buyQuoteFunctionSelector == bytes4(0)) {
|
||||
// Buys not supported on this curve, so approximate it.
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(toTokenIdx, curveInfo),
|
||||
takerTokenData: abi.encode(fromTokenIdx, curveInfo),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromCurve
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
curveInfo.poolAddress.staticcall.gas(CURVE_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
curveInfo.buyQuoteFunctionSelector,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
makerTokenAmounts[i]
|
||||
));
|
||||
uint256 sellAmount = 0;
|
||||
if (didSucceed) {
|
||||
sellAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
takerTokenAmounts[i] = sellAmount;
|
||||
// Break early if there are 0 amounts
|
||||
if (takerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromCurve(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(int128 takerTokenIdx, CurveInfo memory curveInfo) =
|
||||
abi.decode(takerTokenData, (int128, CurveInfo));
|
||||
(int128 makerTokenIdx) =
|
||||
abi.decode(makerTokenData, (int128));
|
||||
(bool success, bytes memory resultData) =
|
||||
address(this).staticcall(abi.encodeWithSelector(
|
||||
this.sampleSellsFromCurve.selector,
|
||||
curveInfo,
|
||||
takerTokenIdx,
|
||||
makerTokenIdx,
|
||||
_toSingleValueArray(sellAmount)
|
||||
));
|
||||
if (!success) {
|
||||
return 0;
|
||||
}
|
||||
// solhint-disable-next-line indent
|
||||
return abi.decode(resultData, (uint256[]))[0];
|
||||
}
|
||||
}
|
||||
|
@@ -1,112 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinCurveV2.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
|
||||
contract CurveV2Sampler is
|
||||
MixinCurveV2,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
function sampleSwapFromCurveV2(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeCurveV2(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Curve.
|
||||
/// @param curveInfo Curve information specific to this token pair.
|
||||
/// @param takerToken The taker token to sell.
|
||||
/// @param makerToken The maker token to buy.
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromCurveV2(
|
||||
CurveBridgeDataV2 memory curveInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(curveInfo),
|
||||
getSwapQuoteCallback: this.sampleSwapFromCurveV2
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Curve.
|
||||
/// @param curveInfo Curve information specific to this token pair.
|
||||
/// @param takerToken The taker token to sell.
|
||||
/// @param makerToken The maker token to buy.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromCurveV2(
|
||||
CurveBridgeDataV2 memory curveInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(curveInfo),
|
||||
buyTokenData: abi.encode(
|
||||
CurveBridgeDataV2({
|
||||
curveAddress: curveInfo.curveAddress,
|
||||
exchangeFunctionSelector: curveInfo.exchangeFunctionSelector,
|
||||
fromCoinIdx: curveInfo.toCoinIdx,
|
||||
toCoinIdx: curveInfo.fromCoinIdx
|
||||
})
|
||||
),
|
||||
getSwapQuoteCallback: this.sampleSwapFromCurveV2
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
}
|
@@ -20,40 +20,35 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinDodo.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
interface IDODOZoo {
|
||||
function getDODO(address baseToken, address quoteToken) external view returns (address);
|
||||
}
|
||||
|
||||
interface IDODOHelper {
|
||||
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
interface IDODO {
|
||||
function querySellBaseToken(uint256 amount) external view returns (uint256);
|
||||
function _TRADE_ALLOWED_() external view returns (bool);
|
||||
}
|
||||
|
||||
contract DODOSampler is
|
||||
MixinDodo,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
/// @dev Gas limit for DODO calls.
|
||||
uint256 constant private DODO_CALL_GAS = 300e3; // 300k
|
||||
struct DODOSamplerOpts {
|
||||
address registry;
|
||||
address helper;
|
||||
}
|
||||
|
||||
function sampleSwapFromDodo(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeDodo(
|
||||
IERC20TokenV06(sellToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from DODO.
|
||||
/// @param opts DODOSamplerOpts DODO Registry and helper addresses
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
@@ -61,7 +56,6 @@ contract DODOSampler is
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromDODO(
|
||||
@@ -71,13 +65,13 @@ contract DODOSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
pool = IDODOZoo(opts.registry).getDODO(takerToken, makerToken);
|
||||
address baseToken;
|
||||
// If pool exists we have the correct order of Base/Quote
|
||||
@@ -88,21 +82,29 @@ contract DODOSampler is
|
||||
pool = IDODOZoo(opts.registry).getDODO(makerToken, takerToken);
|
||||
// No pool either direction
|
||||
if (address(pool) == address(0)) {
|
||||
return (sellBase, pool, gasUsed, makerTokenAmounts);
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
}
|
||||
baseToken = makerToken;
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(opts.helper, pool, sellBase),
|
||||
getSwapQuoteCallback: this.sampleSwapFromDodo
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
// DODO Pool has been disabled
|
||||
if (!IDODO(pool)._TRADE_ALLOWED_()) {
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = _sampleSellForApproximateBuyFromDODO(
|
||||
abi.encode(takerToken, pool, baseToken, opts.helper), // taker token data
|
||||
abi.encode(makerToken, pool, baseToken, opts.helper), // maker token data
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from DODO.
|
||||
@@ -112,7 +114,6 @@ contract DODOSampler is
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromDODO(
|
||||
@@ -122,13 +123,13 @@ contract DODOSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// Pool is BASE/QUOTE
|
||||
// Look up the pool from the taker/maker combination
|
||||
pool = IDODOZoo(opts.registry).getDODO(takerToken, makerToken);
|
||||
@@ -142,21 +143,69 @@ contract DODOSampler is
|
||||
pool = IDODOZoo(opts.registry).getDODO(makerToken, takerToken);
|
||||
// No pool either direction
|
||||
if (address(pool) == address(0)) {
|
||||
return (sellBase, pool, gasUsed, takerTokenAmounts);
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
}
|
||||
baseToken = makerToken;
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(opts.helper, pool, sellBase),
|
||||
buyTokenData: abi.encode(opts.helper, pool, !sellBase),
|
||||
getSwapQuoteCallback: this.sampleSwapFromDodo
|
||||
// DODO Pool has been disabled
|
||||
if (!IDODO(pool)._TRADE_ALLOWED_()) {
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
}
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, pool, baseToken, opts.helper),
|
||||
takerTokenData: abi.encode(takerToken, pool, baseToken, opts.helper),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromDODO
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromDODO(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory /* makerTokenData */,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(address takerToken, address pool, address baseToken, address helper) = abi.decode(
|
||||
takerTokenData,
|
||||
(address, address, address, address)
|
||||
);
|
||||
|
||||
// We will get called to sell both the taker token and also to sell the maker token
|
||||
if (takerToken == baseToken) {
|
||||
// If base token then use the original query on the pool
|
||||
try
|
||||
IDODO(pool).querySellBaseToken
|
||||
{gas: DODO_CALL_GAS}
|
||||
(sellAmount)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
return amount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// If quote token then use helper, this is less accurate
|
||||
try
|
||||
IDODOHelper(helper).querySellQuoteToken
|
||||
{gas: DODO_CALL_GAS}
|
||||
(pool, sellAmount)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
return amount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,8 +20,8 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinDodoV2.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
interface IDODOV2Registry {
|
||||
function getDODOPool(address baseToken, address quoteToken)
|
||||
@@ -30,30 +30,26 @@ interface IDODOV2Registry {
|
||||
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
|
||||
MixinDodoV2,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
/// @dev Gas limit for DODO V2 calls.
|
||||
uint256 constant private DODO_V2_CALL_GAS = 300e3; // 300k
|
||||
|
||||
function sampleSwapFromDodoV2(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeDodoV2(
|
||||
IERC20TokenV06(sellToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @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.
|
||||
@@ -62,7 +58,6 @@ contract DODOV2Sampler is
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromDODOV2(
|
||||
@@ -73,27 +68,31 @@ contract DODOV2Sampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
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, gasUsed, makerTokenAmounts);
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
}
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(pool, sellBase),
|
||||
getSwapQuoteCallback: this.sampleSwapFromDodoV2
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
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]
|
||||
);
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from DODO.
|
||||
@@ -104,7 +103,6 @@ contract DODOV2Sampler is
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromDODOV2(
|
||||
@@ -115,30 +113,68 @@ contract DODOV2Sampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
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, gasUsed, takerTokenAmounts);
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
}
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(pool, sellBase),
|
||||
buyTokenData: abi.encode(pool, !sellBase),
|
||||
getSwapQuoteCallback: this.sampleSwapFromDodoV2
|
||||
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,
|
||||
|
@@ -1,26 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity ^0.6;
|
||||
|
||||
contract DelegateHackedERC20 {
|
||||
|
||||
address private constant HACKED = 0xDEf1000000000000000000000000000000DE7d37;
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
fallback() payable external {
|
||||
(bool success, bytes memory resultData) =
|
||||
HACKED.delegatecall(msg.data);
|
||||
if (!success) {
|
||||
assembly { revert(add(resultData, 32), mload(resultData)) }
|
||||
}
|
||||
assembly { return(add(resultData, 32), mload(resultData)) }
|
||||
}
|
||||
|
||||
/// @dev Hack to get around schema validation
|
||||
function _garbage()
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -23,9 +23,7 @@ pragma experimental ABIEncoderV2;
|
||||
import "./BalancerSampler.sol";
|
||||
import "./BalancerV2Sampler.sol";
|
||||
import "./BancorSampler.sol";
|
||||
import "./BoosterSampler.sol";
|
||||
import "./CurveSampler.sol";
|
||||
import "./CurveV2Sampler.sol";
|
||||
import "./DODOSampler.sol";
|
||||
import "./DODOV2Sampler.sol";
|
||||
import "./Eth2DaiSampler.sol";
|
||||
@@ -34,25 +32,24 @@ import "./KyberDmmSampler.sol";
|
||||
import "./LidoSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
import "./MakerPSMSampler.sol";
|
||||
import "./MultiBridgeSampler.sol";
|
||||
import "./MStableSampler.sol";
|
||||
import "./MooniswapSampler.sol";
|
||||
import "./NativeOrderSampler.sol";
|
||||
import "./ShellSampler.sol";
|
||||
import "./SmoothySampler.sol";
|
||||
import "./TwoHopSampler.sol";
|
||||
import "./UniswapSampler.sol";
|
||||
import "./UniswapV2Sampler.sol";
|
||||
import "./UniswapV3Sampler.sol";
|
||||
import "./UtilitySampler.sol";
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
|
||||
contract ERC20BridgeSampler is
|
||||
BalancerSampler,
|
||||
BalancerV2Sampler,
|
||||
BancorSampler,
|
||||
BoosterSampler,
|
||||
CurveSampler,
|
||||
CurveV2Sampler,
|
||||
DODOSampler,
|
||||
DODOV2Sampler,
|
||||
Eth2DaiSampler,
|
||||
@@ -63,8 +60,10 @@ contract ERC20BridgeSampler is
|
||||
MakerPSMSampler,
|
||||
MStableSampler,
|
||||
MooniswapSampler,
|
||||
MultiBridgeSampler,
|
||||
NativeOrderSampler,
|
||||
ShellSampler,
|
||||
SmoothySampler,
|
||||
TwoHopSampler,
|
||||
UniswapSampler,
|
||||
UniswapV2Sampler,
|
||||
@@ -77,22 +76,11 @@ contract ERC20BridgeSampler is
|
||||
bool success;
|
||||
}
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
BancorSampler(weth)
|
||||
CurveSampler(weth)
|
||||
KyberSampler(weth)
|
||||
MooniswapSampler(weth)
|
||||
LidoSampler(weth)
|
||||
UniswapSampler(weth)
|
||||
{ }
|
||||
|
||||
/// @dev Call multiple public functions on this contract in a single transaction.
|
||||
/// @param callDatas ABI-encoded call data for each function call.
|
||||
/// @return callResults ABI-encoded results data for each call.
|
||||
function batchCall(bytes[] calldata callDatas)
|
||||
external
|
||||
payable
|
||||
returns (CallResults[] memory callResults)
|
||||
{
|
||||
callResults = new CallResults[](callDatas.length);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,38 +20,21 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinOasis.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./interfaces/IEth2Dai.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract Eth2DaiSampler is
|
||||
MixinOasis,
|
||||
SwapRevertSampler
|
||||
SamplerUtils
|
||||
{
|
||||
|
||||
function sampleSwapFromOasis(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeOasis(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Base gas limit for Eth2Dai calls.
|
||||
uint256 constant private ETH2DAI_CALL_GAS = 1000e3; // 1m
|
||||
|
||||
/// @dev Sample sell quotes from Eth2Dai/Oasis.
|
||||
/// @param router Address of the Eth2Dai/Oasis contract
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromEth2Dai(
|
||||
@@ -61,17 +44,29 @@ contract Eth2DaiSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromOasis
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IEth2Dai(router).getBuyAmount
|
||||
{gas: ETH2DAI_CALL_GAS}
|
||||
(makerToken, takerToken, takerTokenAmounts[i])
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Eth2Dai/Oasis.
|
||||
@@ -79,7 +74,6 @@ contract Eth2DaiSampler is
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromEth2Dai(
|
||||
@@ -89,17 +83,28 @@ contract Eth2DaiSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(router),
|
||||
buyTokenData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromOasis
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IEth2Dai(router).getPayAmount
|
||||
{gas: ETH2DAI_CALL_GAS}
|
||||
(takerToken, makerToken, makerTokenAmounts[i])
|
||||
returns (uint256 amount)
|
||||
{
|
||||
takerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (takerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,30 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity ^0.6;
|
||||
|
||||
contract GasOverhead {
|
||||
uint256 private _overhead = 2;
|
||||
// Overhead incurred from updating the overhead storage slot
|
||||
uint256 constant SSTORE_OVERHEAD = 20000;
|
||||
|
||||
function addOverhead(uint256 gas, uint256 gasBefore)
|
||||
external
|
||||
{
|
||||
uint256 callOverhead = gasBefore - gasleft();
|
||||
// Add additional est overhead of performing this update
|
||||
_overhead += gas + callOverhead + SSTORE_OVERHEAD;
|
||||
}
|
||||
|
||||
function clearOverhead()
|
||||
external
|
||||
{
|
||||
_overhead = 2;
|
||||
}
|
||||
|
||||
function overhead()
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return _overhead;
|
||||
}
|
||||
}
|
@@ -1,323 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity ^0.6;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "./GasOverhead.sol";
|
||||
|
||||
contract HackedERC20 {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
struct ShadowedAmount {
|
||||
bool isShadowed;
|
||||
uint256 lastTrueAmount;
|
||||
uint256 shadowedAmount;
|
||||
}
|
||||
|
||||
struct Storage {
|
||||
mapping(address=>ShadowedAmount) shadowedBalances;
|
||||
mapping(address=>mapping(address=>ShadowedAmount)) shadowedAllowances;
|
||||
// When enabled the HackedERC20 token will shadow and track balances
|
||||
// when disabled (default) it will call the original implementation
|
||||
bool enabled;
|
||||
}
|
||||
|
||||
bytes32 private constant STORAGE_SLOT = 0x64fd48372774b9637ace5c8c7a951f04ea13c793935207f2eada5382a0ec82cb;
|
||||
GasOverhead private constant GAS_OVERHEAD = GasOverhead(0xDeF1000000000000000000000000000000001337);
|
||||
|
||||
// HackedERC20 also has the overhead of being Delegated to from the replaced token
|
||||
// USDT->DelegateHackedERC20->HackedERC20
|
||||
uint256 private constant DELEGATE_CALL_OVERHEAD = 5000;
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
fallback() payable external {
|
||||
bytes memory r = _forwardCallToImpl();
|
||||
assembly { return(add(r, 32), mload(r)) }
|
||||
}
|
||||
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
/* view */
|
||||
returns (uint256 balance)
|
||||
{
|
||||
if (!_isEnabled()) {
|
||||
bytes memory r = _forwardCallToImpl();
|
||||
assembly { return(add(r, 32), mload(r)) }
|
||||
}
|
||||
(ShadowedAmount memory sBal,) = _getSyncedBalance(owner);
|
||||
return sBal.shadowedAmount;
|
||||
}
|
||||
|
||||
function allowance(address owner, address spender)
|
||||
external
|
||||
/* view */
|
||||
returns (uint256 allowance_)
|
||||
{
|
||||
if (!_isEnabled()) {
|
||||
bytes memory r = _forwardCallToImpl();
|
||||
assembly { return(add(r, 32), mload(r)) }
|
||||
}
|
||||
(ShadowedAmount memory sBal,) = _getSyncedAllowance(owner, spender);
|
||||
return sBal.shadowedAmount;
|
||||
}
|
||||
|
||||
function transferFrom(address from, address to, uint256 amount)
|
||||
public
|
||||
returns (bool success)
|
||||
{
|
||||
if (!_isEnabled()) {
|
||||
bytes memory r = _forwardCallToImpl();
|
||||
assembly { return(add(r, 32), mload(r)) }
|
||||
}
|
||||
_updateAllowance(from, amount);
|
||||
success = _transferFromInternal(from, to, amount);
|
||||
}
|
||||
|
||||
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool success)
|
||||
{
|
||||
if (!_isEnabled()) {
|
||||
bytes memory r = _forwardCallToImpl();
|
||||
assembly { return(add(r, 32), mload(r)) }
|
||||
}
|
||||
success = _transferFromInternal(msg.sender, to, amount);
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
if (!_isEnabled()) {
|
||||
bytes memory r = _forwardCallToImpl();
|
||||
assembly { return(add(r, 32), mload(r)) }
|
||||
}
|
||||
(
|
||||
ShadowedAmount memory sAllowance,
|
||||
) = _getSyncedAllowance(msg.sender, spender);
|
||||
|
||||
sAllowance.shadowedAmount = amount;
|
||||
_writeSyncedAllowance(msg.sender, spender, sAllowance);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function _setBalance(address owner, uint256 amount)
|
||||
public
|
||||
{
|
||||
(ShadowedAmount memory sBal,) = _getSyncedBalance(owner);
|
||||
sBal.shadowedAmount = amount;
|
||||
_writeSyncedBalance(owner, sBal);
|
||||
}
|
||||
|
||||
|
||||
function _getSyncedAllowance(address owner, address spender)
|
||||
private
|
||||
/* view */
|
||||
returns (ShadowedAmount memory sAllowance, uint256 gasOverhead)
|
||||
{
|
||||
uint256 trueAmount = abi.decode(
|
||||
_forwardCallToImpl(abi.encodeWithSelector(
|
||||
IERC20TokenV06.allowance.selector,
|
||||
owner,
|
||||
spender
|
||||
)),
|
||||
(uint256)
|
||||
);
|
||||
// We only want to measure the cost of the underlying token storage lookup
|
||||
// Not including the excess overhead of our shadow lookup
|
||||
uint256 gasBefore = gasleft();
|
||||
sAllowance = _getStorage().shadowedAllowances[owner][spender];
|
||||
_syncShadowedAmount(sAllowance, trueAmount);
|
||||
gasOverhead = gasBefore - gasleft();
|
||||
}
|
||||
|
||||
function _getSyncedBalance(address owner)
|
||||
private
|
||||
returns (ShadowedAmount memory sBal, uint256 gasOverhead)
|
||||
{
|
||||
uint256 trueAmount = abi.decode(
|
||||
_forwardCallToImpl(abi.encodeWithSelector(
|
||||
IERC20TokenV06.balanceOf.selector,
|
||||
owner
|
||||
)),
|
||||
(uint256)
|
||||
);
|
||||
// We only want to measure the cost of the underlying token storage lookup
|
||||
// Not including the excess overhead of our shadow lookup
|
||||
uint256 gasBefore = gasleft();
|
||||
sBal = _getStorage().shadowedBalances[owner];
|
||||
_syncShadowedAmount(sBal, trueAmount);
|
||||
gasOverhead = gasBefore - gasleft();
|
||||
}
|
||||
|
||||
function _syncShadowedAmount(ShadowedAmount memory sAmount, uint256 trueAmount)
|
||||
private
|
||||
pure
|
||||
{
|
||||
if (!sAmount.isShadowed) {
|
||||
sAmount.isShadowed = true;
|
||||
sAmount.shadowedAmount = trueAmount;
|
||||
} else {
|
||||
// Detect balance changes that can occur from outside of ERC20
|
||||
// functions.
|
||||
if (sAmount.lastTrueAmount > trueAmount) {
|
||||
sAmount.shadowedAmount = _sub(
|
||||
sAmount.lastTrueAmount,
|
||||
sAmount.lastTrueAmount - trueAmount,
|
||||
'HackedERC20/SHADOW_ADJUSTMENT_UNDERFLOW'
|
||||
);
|
||||
} else if (sAmount.lastTrueAmount < trueAmount) {
|
||||
sAmount.shadowedAmount = _add(
|
||||
sAmount.lastTrueAmount,
|
||||
trueAmount - sAmount.lastTrueAmount,
|
||||
'HackedERC20/SHADOW_ADJUSTMENT_OVERFLOW'
|
||||
);
|
||||
}
|
||||
}
|
||||
sAmount.lastTrueAmount = trueAmount;
|
||||
}
|
||||
|
||||
function _writeSyncedBalance(address owner, ShadowedAmount memory sBal)
|
||||
private
|
||||
{
|
||||
_getStorage().shadowedBalances[owner] = sBal;
|
||||
}
|
||||
|
||||
function _writeSyncedAllowance(
|
||||
address owner,
|
||||
address spender,
|
||||
ShadowedAmount memory sAllowance
|
||||
)
|
||||
private
|
||||
{
|
||||
_getStorage().shadowedAllowances[owner][spender] = sAllowance;
|
||||
}
|
||||
|
||||
function _getStorage() private pure returns (Storage storage st) {
|
||||
bytes32 slot = STORAGE_SLOT;
|
||||
assembly { st_slot := slot }
|
||||
}
|
||||
|
||||
function _getOriginalImplementationAddress()
|
||||
private
|
||||
view
|
||||
returns (address impl)
|
||||
{
|
||||
return address(uint160(address(this)) + 1);
|
||||
}
|
||||
|
||||
function _forwardCallToImpl()
|
||||
private
|
||||
returns (bytes memory resultData)
|
||||
{
|
||||
bool success;
|
||||
(success, resultData) =
|
||||
_getOriginalImplementationAddress().delegatecall(msg.data);
|
||||
if (!success) {
|
||||
assembly { revert(add(resultData, 32), mload(resultData)) }
|
||||
}
|
||||
}
|
||||
|
||||
function _forwardCallToImpl(bytes memory callData)
|
||||
private
|
||||
returns (bytes memory resultData)
|
||||
{
|
||||
bool success;
|
||||
(success, resultData) =
|
||||
_getOriginalImplementationAddress().delegatecall(callData);
|
||||
if (!success) {
|
||||
assembly { revert(add(resultData, 32), mload(resultData)) }
|
||||
}
|
||||
}
|
||||
|
||||
function _transferFromInternal(address from, address to, uint256 amount)
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
ShadowedAmount memory sFromBal;
|
||||
ShadowedAmount memory sToBal;
|
||||
uint256 gasOverhead;
|
||||
uint256 _gasOverhead;
|
||||
|
||||
(sFromBal, _gasOverhead) = _getSyncedBalance(from);
|
||||
gasOverhead += _gasOverhead;
|
||||
sFromBal.shadowedAmount = _sub(
|
||||
sFromBal.shadowedAmount,
|
||||
amount,
|
||||
'HackedERC20/BALANCE_UNDERFLOW'
|
||||
);
|
||||
_writeSyncedBalance(from, sFromBal);
|
||||
|
||||
(sToBal, _gasOverhead) = _getSyncedBalance(to);
|
||||
gasOverhead += _gasOverhead;
|
||||
sToBal.shadowedAmount = _add(
|
||||
sToBal.shadowedAmount,
|
||||
amount,
|
||||
'HackedERC20/BALANCE_OVERFLOW'
|
||||
);
|
||||
_writeSyncedBalance(to, sToBal);
|
||||
|
||||
// Update the global gas overhead from a transfer call
|
||||
try
|
||||
GAS_OVERHEAD.addOverhead(gasOverhead + DELEGATE_CALL_OVERHEAD, gasleft())
|
||||
{ } catch { }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function _updateAllowance(address from, uint256 amount)
|
||||
internal
|
||||
{
|
||||
(ShadowedAmount memory sAllowance, uint256 gasOverhead) = _getSyncedAllowance(from, msg.sender);
|
||||
if (from != msg.sender && sAllowance.shadowedAmount != uint256(-1)) {
|
||||
sAllowance.shadowedAmount = _sub(
|
||||
sAllowance.shadowedAmount,
|
||||
amount,
|
||||
'HackedERC20/ALLOWANCE_UNDERFLOW'
|
||||
);
|
||||
_writeSyncedAllowance(from, msg.sender, sAllowance);
|
||||
}
|
||||
uint256 gasBefore = gasleft();
|
||||
// Assume a NON MAX_UINT results in allowance update SSTORE
|
||||
_writeSyncedAllowance(from, msg.sender, sAllowance);
|
||||
gasOverhead += gasBefore - gasleft();
|
||||
// Update the global gas overhead from a allowance check
|
||||
try
|
||||
GAS_OVERHEAD.addOverhead(gasOverhead + DELEGATE_CALL_OVERHEAD, gasleft())
|
||||
{ } catch { }
|
||||
}
|
||||
|
||||
function _isEnabled()
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
return _getStorage().enabled;
|
||||
}
|
||||
|
||||
function _setEnabled(bool enabled)
|
||||
public
|
||||
{
|
||||
_getStorage().enabled = enabled;
|
||||
}
|
||||
|
||||
function _add(uint256 a, uint256 b, string memory errMsg)
|
||||
private
|
||||
pure
|
||||
returns (uint256 c)
|
||||
{
|
||||
c = a + b;
|
||||
require(c >= a, errMsg);
|
||||
}
|
||||
|
||||
function _sub(uint256 a, uint256 b, string memory errMsg)
|
||||
private
|
||||
pure
|
||||
returns (uint256 c)
|
||||
{
|
||||
c = a - b;
|
||||
require(c <= a, errMsg);
|
||||
}
|
||||
}
|
@@ -20,46 +20,49 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinKyberDmm.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
interface IKyberDmmFactory {
|
||||
interface IKyberDmmPool {
|
||||
|
||||
function getPoolAtIndex(address token0, address token1, uint256 index)
|
||||
function totalSupply()
|
||||
external
|
||||
view
|
||||
returns (address);
|
||||
returns (uint256);
|
||||
}
|
||||
|
||||
interface IKyberDmmFactory {
|
||||
|
||||
function getPools(address token0, address token1)
|
||||
external
|
||||
view
|
||||
returns (address[] memory _tokenPools);
|
||||
}
|
||||
|
||||
interface IKyberDmmRouter {
|
||||
|
||||
function factory() external view returns (address);
|
||||
|
||||
function getAmountsOut(uint256 amountIn, address[] calldata pools, address[] calldata path)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory amounts);
|
||||
|
||||
function getAmountsIn(uint256 amountOut, address[] calldata pools, address[] calldata path)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory amounts);
|
||||
}
|
||||
|
||||
|
||||
contract KyberDmmSampler is
|
||||
MixinKyberDmm,
|
||||
SwapRevertSampler
|
||||
|
||||
contract KyberDmmSampler
|
||||
{
|
||||
/// @dev Gas limit for KyberDmm calls.
|
||||
uint256 constant private KYBER_DMM_CALL_GAS = 150e3; // 150k
|
||||
|
||||
function sampleSwapFromKyberDmm(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeKyberDmm(
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from KyberDmm.
|
||||
/// @param router Router to look up tokens and amounts
|
||||
/// @param path Token route. Should be takerToken -> makerToken
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return pools The pool addresses involved in the multi path trade
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromKyberDmm(
|
||||
@@ -68,26 +71,32 @@ contract KyberDmmSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
address[] memory pools,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
view
|
||||
returns (address[] memory pools, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
pools = _getKyberDmmPools(router, path);
|
||||
if (pools.length == 0) {
|
||||
return (pools, gasUsed, makerTokenAmounts);
|
||||
return (pools, makerTokenAmounts);
|
||||
}
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IKyberDmmRouter(router).getAmountsOut
|
||||
{gas: KYBER_DMM_CALL_GAS}
|
||||
(takerTokenAmounts[i], pools, path)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
makerTokenAmounts[i] = amounts[path.length - 1];
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: path[0],
|
||||
buyToken: path[path.length - 1],
|
||||
bridgeData: abi.encode(router, pools, path),
|
||||
getSwapQuoteCallback: this.sampleSwapFromKyberDmm
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from KyberDmm.
|
||||
@@ -95,7 +104,6 @@ contract KyberDmmSampler is
|
||||
/// @param path Token route. Should be takerToken -> makerToken.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return pools The pool addresses involved in the multi path trade
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromKyberDmm(
|
||||
@@ -104,32 +112,32 @@ contract KyberDmmSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
address[] memory pools,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
view
|
||||
returns (address[] memory pools, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
pools = _getKyberDmmPools(router, path);
|
||||
if (pools.length == 0) {
|
||||
return (pools, gasUsed, takerTokenAmounts);
|
||||
return (pools, takerTokenAmounts);
|
||||
}
|
||||
|
||||
address[] memory reversedPath = new address[](path.length);
|
||||
for (uint256 i = 0; i < path.length; ++i) {
|
||||
reversedPath[i] = path[path.length - i - 1];
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IKyberDmmRouter(router).getAmountsIn
|
||||
{gas: KYBER_DMM_CALL_GAS}
|
||||
(makerTokenAmounts[i], pools, path)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
takerTokenAmounts[i] = amounts[0];
|
||||
// Break early if there are 0 amounts
|
||||
if (takerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
address[] memory reversedPools = _getKyberDmmPools(router, reversedPath);
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: path[0],
|
||||
buyToken: path[path.length - 1],
|
||||
sellTokenData: abi.encode(router, pools, path),
|
||||
buyTokenData: abi.encode(router, reversedPools, reversedPath),
|
||||
getSwapQuoteCallback: this.sampleSwapFromKyberDmm
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _getKyberDmmPools(
|
||||
@@ -140,17 +148,26 @@ contract KyberDmmSampler is
|
||||
view
|
||||
returns (address[] memory pools)
|
||||
{
|
||||
pools = new address[](path.length - 1);
|
||||
IKyberDmmFactory factory = IKyberDmmFactory(IKyberDmmRouter(router).factory());
|
||||
pools = new address[](path.length - 1);
|
||||
for (uint256 i = 0; i < pools.length; i++) {
|
||||
// Currently only supporting the first pool found at the index
|
||||
// find the best pool
|
||||
address[] memory allPools;
|
||||
try
|
||||
factory.getPoolAtIndex
|
||||
factory.getPools
|
||||
{gas: KYBER_DMM_CALL_GAS}
|
||||
(path[i], path[i + 1], 0)
|
||||
returns (address pool)
|
||||
(path[i], path[i + 1])
|
||||
returns (address[] memory allPools)
|
||||
{
|
||||
pools[i] = pool;
|
||||
uint256 maxSupply = 0;
|
||||
require(allPools.length >= 1, "KyberDMMSampler/NO_POOLS_FOUND");
|
||||
for (uint256 j = 0; j < allPools.length; j++) {
|
||||
uint256 totalSupply = IKyberDmmPool(allPools[j]).totalSupply();
|
||||
if (totalSupply > maxSupply) {
|
||||
maxSupply = totalSupply;
|
||||
pools[i] = allPools[j];
|
||||
}
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
return new address[](0);
|
||||
}
|
||||
|
@@ -21,22 +21,18 @@ pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IKyberNetwork.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinKyber.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract KyberSampler is
|
||||
MixinKyber,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
/// @dev Gas limit for Kyber calls.
|
||||
uint256 constant private KYBER_CALL_GAS = 500e3; // 500k
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinKyber(weth)
|
||||
{ }
|
||||
|
||||
struct KyberSamplerOpts {
|
||||
uint256 reserveOffset;
|
||||
@@ -46,26 +42,6 @@ contract KyberSampler is
|
||||
bytes hint;
|
||||
}
|
||||
|
||||
function sampleSwapFromKyber(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeKyberInternal(
|
||||
// these are Immutable in MixinKyber, since they are only set in constructor they must be passed in
|
||||
IERC20TokenV06(KYBER_ETH_ADDRESS),
|
||||
_getNativeWrappedToken(),
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Kyber.
|
||||
/// @param opts KyberSamplerOpts The nth reserve
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
@@ -73,7 +49,6 @@ contract KyberSampler is
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return reserveId The id of the reserve found at reserveOffset
|
||||
/// @return hint The hint for the selected reserve
|
||||
/// @return gasUsed Gas consumed per sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token amount.
|
||||
function sampleSellsFromKyberNetwork(
|
||||
KyberSamplerOpts memory opts,
|
||||
@@ -82,29 +57,32 @@ contract KyberSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bytes32 reserveId,
|
||||
bytes memory hint,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
view
|
||||
returns (bytes32 reserveId, bytes memory hint, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
reserveId = _getNextReserveId(opts, takerToken, makerToken);
|
||||
if (reserveId == 0x0) {
|
||||
return (reserveId, hint, gasUsed, makerTokenAmounts);
|
||||
return (reserveId, hint, makerTokenAmounts);
|
||||
}
|
||||
opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
|
||||
hint = opts.hint;
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(opts.networkProxy, hint),
|
||||
getSwapQuoteCallback: this.sampleSwapFromKyber
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 value = this.sampleSellFromKyberNetwork(
|
||||
opts,
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
makerTokenAmounts[i] = value;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Kyber.
|
||||
@@ -114,7 +92,6 @@ contract KyberSampler is
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return reserveId The id of the reserve found at reserveOffset
|
||||
/// @return hint The hint for the selected reserve
|
||||
/// @return gasUsed Gas consumed for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token amount.
|
||||
function sampleBuysFromKyberNetwork(
|
||||
KyberSamplerOpts memory opts,
|
||||
@@ -123,30 +100,27 @@ contract KyberSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bytes32 reserveId,
|
||||
bytes memory hint,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
view
|
||||
returns (bytes32 reserveId, bytes memory hint, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
reserveId = _getNextReserveId(opts, takerToken, makerToken);
|
||||
if (reserveId == 0x0) {
|
||||
return (reserveId, hint, gasUsed, takerTokenAmounts);
|
||||
return (reserveId, hint, takerTokenAmounts);
|
||||
}
|
||||
opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
|
||||
hint = opts.hint;
|
||||
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(opts.networkProxy, hint),
|
||||
buyTokenData: abi.encode(opts.networkProxy, hint),
|
||||
getSwapQuoteCallback: this.sampleSwapFromKyber
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, opts),
|
||||
takerTokenData: abi.encode(takerToken, opts),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromKyber
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
return (reserveId, hint, takerTokenAmounts);
|
||||
}
|
||||
|
||||
function encodeKyberHint(
|
||||
@@ -227,6 +201,73 @@ contract KyberSampler is
|
||||
}
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromKyber(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(address makerToken, KyberSamplerOpts memory opts) =
|
||||
abi.decode(makerTokenData, (address, KyberSamplerOpts));
|
||||
(address takerToken, ) =
|
||||
abi.decode(takerTokenData, (address, KyberSamplerOpts));
|
||||
try
|
||||
this.sampleSellFromKyberNetwork
|
||||
(opts, takerToken, makerToken, sellAmount)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
return amount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function sampleSellFromKyberNetwork(
|
||||
KyberSamplerOpts memory opts,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256 makerTokenAmount)
|
||||
{
|
||||
// If there is no hint do not continue
|
||||
if (opts.hint.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try
|
||||
IKyberNetworkProxy(opts.networkProxy).getExpectedRateAfterFee
|
||||
{gas: KYBER_CALL_GAS}
|
||||
(
|
||||
takerToken == opts.weth ? KYBER_ETH_ADDRESS : takerToken,
|
||||
makerToken == opts.weth ? KYBER_ETH_ADDRESS : makerToken,
|
||||
takerTokenAmount,
|
||||
0, // fee
|
||||
opts.hint
|
||||
)
|
||||
returns (uint256 rate)
|
||||
{
|
||||
uint256 makerTokenDecimals = _getTokenDecimals(makerToken);
|
||||
uint256 takerTokenDecimals = _getTokenDecimals(takerToken);
|
||||
makerTokenAmount =
|
||||
rate *
|
||||
takerTokenAmount *
|
||||
10 ** makerTokenDecimals /
|
||||
10 ** takerTokenDecimals /
|
||||
10 ** 18;
|
||||
return makerTokenAmount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function _getNextReserveId(
|
||||
KyberSamplerOpts memory opts,
|
||||
address takerToken,
|
||||
|
@@ -20,84 +20,72 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinLido.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
contract LidoSampler is
|
||||
MixinLido,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinLido(weth)
|
||||
{ }
|
||||
|
||||
function sampleSwapFromLido(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeLidoInternal(
|
||||
_getNativeWrappedToken(),
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
contract LidoSampler is SamplerUtils {
|
||||
struct LidoInfo {
|
||||
address stEthToken;
|
||||
address wethToken;
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Lido
|
||||
/// @param lido Address of the Lido contract
|
||||
/// @param lidoInfo Info regarding a specific Lido deployment
|
||||
/// @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 gasUsed gas consumed for each sample amount
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromLido(
|
||||
address lido,
|
||||
LidoInfo memory lidoInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
pure
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(lido),
|
||||
getSwapQuoteCallback: this.sampleSwapFromLido
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
if (takerToken != lidoInfo.wethToken || makerToken != address(lidoInfo.stEthToken)) {
|
||||
// Return 0 values if not selling WETH for stETH
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
uint256[] memory makerTokenAmounts = new uint256[](numSamples);
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
// Minting stETH is always 1:1 therefore we can just return the same amounts back
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Lido.
|
||||
/// @param lido Address of the Lido contract
|
||||
/// @param lidoInfo Info regarding a specific Lido deployment
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed for each sample amount
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromLido(
|
||||
address lido,
|
||||
LidoInfo memory lidoInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
pure
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
// 1:1 rate so we can perform an WETH sell
|
||||
return this.sampleSellsFromLido(lido, takerToken, makerToken, makerTokenAmounts);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
if (takerToken != lidoInfo.wethToken || makerToken != address(lidoInfo.stEthToken)) {
|
||||
// Return 0 values if not buying stETH for WETH
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
uint256[] memory takerTokenAmounts = new uint256[](numSamples);
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
// Minting stETH is always 1:1 therefore we can just return the same amounts back
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,38 +20,24 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinZeroExBridge.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/vendor/ILiquidityProvider.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract LiquidityProviderSampler is
|
||||
MixinZeroExBridge,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
function sampleSwapFromLiquidityProvider(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeZeroExBridge(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Default gas limit for liquidity provider calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
||||
|
||||
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
|
||||
/// @param providerAddress Address of the liquidity provider.
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromLiquidityProvider(
|
||||
@@ -61,18 +47,34 @@ contract LiquidityProviderSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
bytes memory lpData;
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(providerAddress, lpData),
|
||||
getSwapQuoteCallback: this.sampleSwapFromLiquidityProvider
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
ILiquidityProvider(providerAddress).getSellQuote
|
||||
{gas: DEFAULT_CALL_GAS}
|
||||
(
|
||||
IERC20TokenV06(takerToken),
|
||||
IERC20TokenV06(makerToken),
|
||||
takerTokenAmounts[i]
|
||||
)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
||||
@@ -80,7 +82,6 @@ contract LiquidityProviderSampler is
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromLiquidityProvider(
|
||||
@@ -90,18 +91,42 @@ contract LiquidityProviderSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
bytes memory lpData;
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(providerAddress, lpData),
|
||||
buyTokenData: abi.encode(providerAddress, lpData),
|
||||
getSwapQuoteCallback: this.sampleSwapFromLiquidityProvider
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, providerAddress),
|
||||
takerTokenData: abi.encode(takerToken, providerAddress),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProvider
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromLiquidityProvider(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(address takerToken, address providerAddress) =
|
||||
abi.decode(takerTokenData, (address, address));
|
||||
(address makerToken) =
|
||||
abi.decode(makerTokenData, (address));
|
||||
try
|
||||
this.sampleSellsFromLiquidityProvider
|
||||
{gas: DEFAULT_CALL_GAS}
|
||||
(providerAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
return amounts[0];
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,38 +20,23 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinMStable.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./interfaces/IMStable.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract MStableSampler is
|
||||
MixinMStable,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
function sampleSwapFromMStable(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeMStable(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Default gas limit for mStable calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 800e3; // 800k
|
||||
|
||||
/// @dev Sample sell quotes from the mStable contract
|
||||
/// @param router Address of the mStable contract
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromMStable(
|
||||
@@ -61,17 +46,31 @@ contract MStableSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMStable
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IMStable(router).getSwapOutput
|
||||
{gas: DEFAULT_CALL_GAS}
|
||||
(takerToken, makerToken, takerTokenAmounts[i])
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from MStable contract
|
||||
@@ -79,7 +78,6 @@ contract MStableSampler is
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromMStable(
|
||||
@@ -89,17 +87,41 @@ contract MStableSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(router),
|
||||
buyTokenData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMStable
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, router),
|
||||
takerTokenData: abi.encode(takerToken, router),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromMStable
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromMStable(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(address takerToken, address router) =
|
||||
abi.decode(takerTokenData, (address, address));
|
||||
(address makerToken) =
|
||||
abi.decode(makerTokenData, (address));
|
||||
try
|
||||
this.sampleSellsFromMStable
|
||||
(router, takerToken, makerToken, _toSingleValueArray(sellAmount))
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
return amounts[0];
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,13 +20,69 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
|
||||
|
||||
interface IPSM {
|
||||
// @dev Get the fee for selling USDC to DAI in PSM
|
||||
// @return tin toll in [wad]
|
||||
function tin() external view returns (uint256);
|
||||
// @dev Get the fee for selling DAI to USDC in PSM
|
||||
// @return tout toll out [wad]
|
||||
function tout() external view returns (uint256);
|
||||
|
||||
// @dev Get the address of the PSM state Vat
|
||||
// @return address of the Vat
|
||||
function vat() external view returns (address);
|
||||
|
||||
// @dev Get the address of the underlying vault powering PSM
|
||||
// @return address of gemJoin contract
|
||||
function gemJoin() external view returns (address);
|
||||
|
||||
// @dev Get the address of DAI
|
||||
// @return address of DAI contract
|
||||
function dai() external view returns (address);
|
||||
|
||||
// @dev Sell USDC for DAI
|
||||
// @param usr The address of the account trading USDC for DAI.
|
||||
// @param gemAmt The amount of USDC to sell in USDC base units
|
||||
function sellGem(
|
||||
address usr,
|
||||
uint256 gemAmt
|
||||
) external;
|
||||
// @dev Buy USDC for DAI
|
||||
// @param usr The address of the account trading DAI for USDC
|
||||
// @param gemAmt The amount of USDC to buy in USDC base units
|
||||
function buyGem(
|
||||
address usr,
|
||||
uint256 gemAmt
|
||||
) external;
|
||||
}
|
||||
|
||||
interface IVAT {
|
||||
// @dev Get a collateral type by identifier
|
||||
// @param ilkIdentifier bytes32 identifier. Example: ethers.utils.formatBytes32String("PSM-USDC-A")
|
||||
// @return ilk
|
||||
// @return ilk.Art Total Normalised Debt in wad
|
||||
// @return ilk.rate Accumulated Rates in ray
|
||||
// @return ilk.spot Price with Safety Margin in ray
|
||||
// @return ilk.line Debt Ceiling in rad
|
||||
// @return ilk.dust Urn Debt Floor in rad
|
||||
function ilks(
|
||||
bytes32 ilkIdentifier
|
||||
) external view returns (
|
||||
uint256 Art,
|
||||
uint256 rate,
|
||||
uint256 spot,
|
||||
uint256 line,
|
||||
uint256 dust
|
||||
);
|
||||
}
|
||||
|
||||
contract MakerPSMSampler is
|
||||
MixinMakerPSM,
|
||||
SwapRevertSampler
|
||||
SamplerUtils
|
||||
{
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
/// @dev Information about which PSM module to use
|
||||
struct MakerPsmInfo {
|
||||
@@ -35,22 +91,18 @@ contract MakerPSMSampler is
|
||||
address gemTokenAddress;
|
||||
}
|
||||
|
||||
function sampleSwapFromMakerPsm(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeMakerPsm(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Gas limit for MakerPsm calls.
|
||||
uint256 constant private MAKER_PSM_CALL_GAS = 300e3; // 300k
|
||||
|
||||
|
||||
// Maker units
|
||||
// wad: fixed point decimal with 18 decimals (for basic quantities, e.g. balances)
|
||||
uint256 constant private WAD = 10 ** 18;
|
||||
// ray: fixed point decimal with 27 decimals (for precise quantites, e.g. ratios)
|
||||
uint256 constant private RAY = 10 ** 27;
|
||||
// rad: fixed point decimal with 45 decimals (result of integer multiplication with a wad and a ray)
|
||||
uint256 constant private RAD = 10 ** 45;
|
||||
// See https://github.com/makerdao/dss/blob/master/DEVELOPING.m
|
||||
|
||||
/// @dev Sample sell quotes from Maker PSM
|
||||
function sampleSellsFromMakerPsm(
|
||||
@@ -60,22 +112,29 @@ contract MakerPSMSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(
|
||||
MakerPsmBridgeData({
|
||||
psmAddress: psmInfo.psmAddress,
|
||||
gemTokenAddres: psmInfo.gemTokenAddress
|
||||
})
|
||||
),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMakerPsm
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IPSM psm = IPSM(psmInfo.psmAddress);
|
||||
IVAT vat = IVAT(psm.vat());
|
||||
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
if (makerToken != psm.dai() && takerToken != psm.dai()) {
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = _samplePSMSell(psmInfo, makerToken, takerToken, takerTokenAmounts[i], psm, vat);
|
||||
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
function sampleBuysFromMakerPsm(
|
||||
@@ -85,21 +144,124 @@ contract MakerPSMSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
MakerPsmBridgeData memory data = MakerPsmBridgeData({
|
||||
psmAddress: psmInfo.psmAddress,
|
||||
gemTokenAddres: psmInfo.gemTokenAddress
|
||||
});
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(data),
|
||||
buyTokenData: abi.encode(data),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMakerPsm
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IPSM psm = IPSM(psmInfo.psmAddress);
|
||||
IVAT vat = IVAT(psm.vat());
|
||||
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
if (makerToken != psm.dai() && takerToken != psm.dai()) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 sellAmount = _samplePSMBuy(psmInfo, makerToken, takerToken, makerTokenAmounts[i], psm, vat);
|
||||
|
||||
if (sellAmount == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
takerTokenAmounts[i] = sellAmount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _samplePSMSell(MakerPsmInfo memory psmInfo, address makerToken, address takerToken, uint256 takerTokenAmount, IPSM psm, IVAT vat)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(uint256 totalDebtInWad,,, uint256 debtCeilingInRad, uint256 debtFloorInRad) = vat.ilks(psmInfo.ilkIdentifier);
|
||||
uint256 gemTokenBaseUnit = uint256(1e6);
|
||||
|
||||
if (takerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate sellGem
|
||||
// Selling USDC to the PSM, increasing the total debt
|
||||
// Convert USDC 6 decimals to 18 decimals [wad]
|
||||
uint256 takerTokenAmountInWad = takerTokenAmount.safeMul(1e12);
|
||||
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeAdd(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is too full to fit
|
||||
if (newTotalDebtInRad >= debtCeilingInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 feeInWad = takerTokenAmountInWad.safeMul(psm.tin()).safeDiv(WAD);
|
||||
uint256 makerTokenAmountInWad = takerTokenAmountInWad.safeSub(feeInWad);
|
||||
|
||||
return makerTokenAmountInWad;
|
||||
} else if (makerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate buyGem
|
||||
// Buying USDC from the PSM, decreasing the total debt
|
||||
// Selling DAI for USDC, already in 18 decimals [wad]
|
||||
uint256 takerTokenAmountInWad = takerTokenAmount;
|
||||
if (takerTokenAmountInWad > totalDebtInWad) {
|
||||
return 0;
|
||||
}
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeSub(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is empty, not enough USDC to buy from it
|
||||
if (newTotalDebtInRad <= debtFloorInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 feeDivisorInWad = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% tout;
|
||||
uint256 makerTokenAmountInGemTokenBaseUnits = takerTokenAmountInWad.safeMul(gemTokenBaseUnit).safeDiv(feeDivisorInWad);
|
||||
|
||||
return makerTokenAmountInGemTokenBaseUnits;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function _samplePSMBuy(MakerPsmInfo memory psmInfo, address makerToken, address takerToken, uint256 makerTokenAmount, IPSM psm, IVAT vat)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(uint256 totalDebtInWad,,, uint256 debtCeilingInRad, uint256 debtFloorInRad) = vat.ilks(psmInfo.ilkIdentifier);
|
||||
|
||||
if (takerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate sellGem
|
||||
// Selling USDC to the PSM, increasing the total debt
|
||||
uint256 makerTokenAmountInWad = makerTokenAmount;
|
||||
uint256 feeDivisorInWad = WAD.safeSub(psm.tin()); // eg. 0.999 * 10 ** 18 with 0.1% tin;
|
||||
uint256 takerTokenAmountInWad = makerTokenAmountInWad.safeMul(WAD).safeDiv(feeDivisorInWad);
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeAdd(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is too full to fit
|
||||
if (newTotalDebtInRad >= debtCeilingInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 takerTokenAmountInGemInGemBaseUnits = (takerTokenAmountInWad.safeDiv(1e12)).safeAdd(1); // Add 1 to deal with cut off decimals converting to lower decimals
|
||||
|
||||
return takerTokenAmountInGemInGemBaseUnits;
|
||||
} else if (makerToken == psmInfo.gemTokenAddress) {
|
||||
// Simulate buyGem
|
||||
// Buying USDC from the PSM, decreasing the total debt
|
||||
uint256 makerTokenAmountInWad = makerTokenAmount.safeMul(1e12);
|
||||
uint256 feeMultiplierInWad = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% tout;
|
||||
uint256 takerTokenAmountInWad = makerTokenAmountInWad.safeMul(feeMultiplierInWad).safeDiv(WAD);
|
||||
if (takerTokenAmountInWad > totalDebtInWad) {
|
||||
return 0;
|
||||
}
|
||||
uint256 newTotalDebtInRad = totalDebtInWad.safeSub(takerTokenAmountInWad).safeMul(RAY);
|
||||
|
||||
// PSM is empty, not enough USDC to buy
|
||||
if (newTotalDebtInRad <= debtFloorInRad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return takerTokenAmountInWad;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,40 +20,17 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinMooniswap.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./interfaces/IMooniswap.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
interface IMooniswapRegistry {
|
||||
function pools(address token1, address token2) external view returns(address);
|
||||
}
|
||||
|
||||
contract MooniswapSampler is
|
||||
MixinMooniswap,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinMooniswap(weth)
|
||||
{ }
|
||||
|
||||
function sampleSwapFromMooniswap(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeMooniswapInternal(
|
||||
_getNativeWrappedToken(),
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Gas limit for Mooniswap calls.
|
||||
uint256 constant private MOONISWAP_CALL_GAS = 150e3; // 150k
|
||||
|
||||
/// @dev Sample sell quotes from Mooniswap.
|
||||
/// @param registry Address of the Mooniswap Registry.
|
||||
@@ -61,7 +38,6 @@ contract MooniswapSampler is
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return pool The contract address for the pool
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromMooniswap(
|
||||
@@ -71,31 +47,77 @@ contract MooniswapSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (address pool, uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (IMooniswap pool, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
pool = _getMooniswapPool(registry, takerToken, makerToken);
|
||||
if (address(pool) == address(0)) {
|
||||
return (pool, gasUsed, makerTokenAmounts);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = sampleSingleSellFromMooniswapPool(
|
||||
registry,
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMooniswap
|
||||
}),
|
||||
takerTokenAmounts
|
||||
pool = IMooniswap(
|
||||
IMooniswapRegistry(registry).pools(takerToken, makerToken)
|
||||
);
|
||||
}
|
||||
|
||||
function sampleSingleSellFromMooniswapPool(
|
||||
address registry,
|
||||
address mooniswapTakerToken,
|
||||
address mooniswapMakerToken,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
// Find the pool for the pair.
|
||||
IMooniswap pool = IMooniswap(
|
||||
IMooniswapRegistry(registry).pools(mooniswapTakerToken, mooniswapMakerToken)
|
||||
);
|
||||
// If there is no pool then return early
|
||||
if (address(pool) == address(0)) {
|
||||
return 0;
|
||||
}
|
||||
uint256 poolBalance = mooniswapTakerToken == address(0)
|
||||
? address(pool).balance
|
||||
: IERC20TokenV06(mooniswapTakerToken).balanceOf(address(pool));
|
||||
// If the pool balance is smaller than the sell amount
|
||||
// don't sample to avoid multiplication overflow in buys
|
||||
if (poolBalance < takerTokenAmount) {
|
||||
return 0;
|
||||
}
|
||||
try
|
||||
pool.getReturn
|
||||
{gas: MOONISWAP_CALL_GAS}
|
||||
(mooniswapTakerToken, mooniswapMakerToken, takerTokenAmount)
|
||||
returns (uint256 amount)
|
||||
{
|
||||
return amount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Mooniswap.
|
||||
/// @param registry Address of the Mooniswap 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 pool The contract address for the pool
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromMooniswap(
|
||||
@@ -105,42 +127,43 @@ contract MooniswapSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (address pool, uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (IMooniswap pool, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
pool = _getMooniswapPool(registry, takerToken, makerToken);
|
||||
if (address(pool) == address(0)) {
|
||||
return (pool, gasUsed, takerTokenAmounts);
|
||||
}
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(pool),
|
||||
buyTokenData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMooniswap
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(registry, makerToken),
|
||||
takerTokenData: abi.encode(registry, takerToken),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromMooniswap
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
|
||||
pool = IMooniswap(
|
||||
IMooniswapRegistry(registry).pools(takerToken, makerToken)
|
||||
);
|
||||
}
|
||||
|
||||
function _getMooniswapPool(
|
||||
address registry,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
function _sampleSellForApproximateBuyFromMooniswap(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
internal
|
||||
returns (address pool)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
// WETH is actually ETH in these pools and represented as address(0)
|
||||
address _takerToken = takerToken == address(_getNativeWrappedToken()) ? address(0) : takerToken;
|
||||
address _makerToken = makerToken == address(_getNativeWrappedToken()) ? address(0) : makerToken;
|
||||
|
||||
try
|
||||
IMooniswapRegistry(registry).pools{gas: 300e3}(_takerToken, _makerToken)
|
||||
returns (address _pool)
|
||||
{
|
||||
pool = _pool;
|
||||
} catch { }
|
||||
(address registry, address mooniswapTakerToken) = abi.decode(takerTokenData, (address, address));
|
||||
(address _registry, address mooniswapMakerToken) = abi.decode(makerTokenData, (address, address));
|
||||
return sampleSingleSellFromMooniswapPool(
|
||||
registry,
|
||||
mooniswapTakerToken,
|
||||
mooniswapMakerToken,
|
||||
sellAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
82
packages/asset-swapper/contracts/src/MultiBridgeSampler.sol
Normal file
82
packages/asset-swapper/contracts/src/MultiBridgeSampler.sol
Normal file
@@ -0,0 +1,82 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IMultiBridge.sol";
|
||||
|
||||
|
||||
contract MultiBridgeSampler {
|
||||
|
||||
/// @dev Default gas limit for multibridge calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
||||
|
||||
/// @dev Sample sell quotes from MultiBridge.
|
||||
/// @param multibridge Address of the MultiBridge contract.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param intermediateToken The address of the intermediate token to
|
||||
/// use in an indirect route.
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromMultiBridge(
|
||||
address multibridge,
|
||||
address takerToken,
|
||||
address intermediateToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// If no address provided, return all zeros.
|
||||
if (multibridge == address(0)) {
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
multibridge.staticcall.gas(DEFAULT_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IMultiBridge(0).getSellQuote.selector,
|
||||
takerToken,
|
||||
intermediateToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
// Exit early if the amount is too high for the source to serve
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
}
|
58
packages/asset-swapper/contracts/src/SamplerUtils.sol
Normal file
58
packages/asset-swapper/contracts/src/SamplerUtils.sol
Normal file
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
|
||||
|
||||
contract SamplerUtils {
|
||||
|
||||
/// @dev Overridable way to get token decimals.
|
||||
/// @param tokenAddress Address of the token.
|
||||
/// @return decimals The decimal places for the token.
|
||||
function _getTokenDecimals(address tokenAddress)
|
||||
virtual
|
||||
internal
|
||||
view
|
||||
returns (uint8 decimals)
|
||||
{
|
||||
return LibERC20TokenV06.compatDecimals(IERC20TokenV06(tokenAddress));
|
||||
}
|
||||
|
||||
function _toSingleValueArray(uint256 v)
|
||||
internal
|
||||
pure
|
||||
returns (uint256[] memory arr)
|
||||
{
|
||||
arr = new uint256[](1);
|
||||
arr[0] = v;
|
||||
}
|
||||
|
||||
/// @dev Assert that the tokens in a trade pair are valid.
|
||||
/// @param makerToken Address of the maker token.
|
||||
/// @param takerToken Address of the taker token.
|
||||
function _assertValidPair(address makerToken, address takerToken)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
require(makerToken != takerToken, "ERC20BridgeSampler/INVALID_TOKEN_PAIR");
|
||||
}
|
||||
}
|
@@ -20,41 +20,28 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinShell.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./interfaces/IShell.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract ShellSampler is
|
||||
MixinShell,
|
||||
SwapRevertSampler
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
struct ShellInfo {
|
||||
address poolAddress;
|
||||
}
|
||||
|
||||
function sampleSwapFromShell(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeShell(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Default gas limit for Shell calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 300e3; // 300k
|
||||
|
||||
/// @dev Sample sell quotes from the Shell pool contract
|
||||
/// @param pool Address of the Shell pool contract
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromShell(
|
||||
@@ -64,17 +51,26 @@ contract ShellSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromShell
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IShell(pool).viewOriginSwap
|
||||
{gas: DEFAULT_CALL_GAS}
|
||||
(takerToken, makerToken, takerTokenAmounts[i])
|
||||
returns (uint256 amount)
|
||||
{
|
||||
makerTokenAmounts[i] = amount;
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Shell pool contract
|
||||
@@ -82,7 +78,6 @@ contract ShellSampler is
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromShell(
|
||||
@@ -92,17 +87,40 @@ contract ShellSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(pool),
|
||||
buyTokenData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromShell
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, pool),
|
||||
takerTokenData: abi.encode(takerToken, pool),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromShell
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromShell(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(address takerToken, address pool) = abi.decode(takerTokenData, (address, address));
|
||||
(address makerToken) = abi.decode(makerTokenData, (address));
|
||||
|
||||
try
|
||||
this.sampleSellsFromShell
|
||||
(pool, takerToken, makerToken, _toSingleValueArray(sellAmount))
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
return amounts[0];
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
156
packages/asset-swapper/contracts/src/SmoothySampler.sol
Normal file
156
packages/asset-swapper/contracts/src/SmoothySampler.sol
Normal file
@@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
// import "./interfaces/ISmoothy.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "./interfaces/ISmoothy.sol";
|
||||
|
||||
contract SmoothySampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
/// @dev Information for sampling from smoothy sources.
|
||||
struct SmoothyInfo {
|
||||
address poolAddress;
|
||||
bytes4 sellQuoteFunctionSelector;
|
||||
bytes4 buyQuoteFunctionSelector;
|
||||
}
|
||||
|
||||
/// @dev Base gas limit for Smoothy calls.
|
||||
uint256 constant private SMOOTHY_CALL_GAS = 600e3;
|
||||
|
||||
/// @dev Sample sell quotes from Smoothy.
|
||||
/// @param smoothyInfo Smoothy information specific to this token pair.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromSmoothy(
|
||||
SmoothyInfo memory smoothyInfo,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// Basically a Curve fork
|
||||
|
||||
// Smoothy only keep a percentage of its tokens available in reserve
|
||||
uint256 poolReserveMakerAmount = ISmoothy(smoothyInfo.poolAddress).getBalance(uint256(toTokenIdx)) -
|
||||
ISmoothy(smoothyInfo.poolAddress)._yBalances(uint256(toTokenIdx));
|
||||
(, , , uint256 decimals) = ISmoothy(smoothyInfo.poolAddress).getTokenStats(uint256(toTokenIdx));
|
||||
poolReserveMakerAmount = poolReserveMakerAmount/(10**(18-decimals));
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
smoothyInfo.poolAddress.staticcall.gas(SMOOTHY_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
smoothyInfo.sellQuoteFunctionSelector,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
|
||||
// Make sure the quoted buyAmount is available in the pool reserve
|
||||
if (buyAmount >= poolReserveMakerAmount) {
|
||||
// Assign pool reserve amount for all higher samples to break early
|
||||
for (uint256 j = i; j < numSamples; j++) {
|
||||
makerTokenAmounts[j] = poolReserveMakerAmount;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Smoothy.
|
||||
/// @param smoothyInfo Smoothy information specific to this token pair.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromSmoothy(
|
||||
SmoothyInfo memory smoothyInfo,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
// Buys not supported so approximate it.
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(toTokenIdx, smoothyInfo),
|
||||
takerTokenData: abi.encode(fromTokenIdx, smoothyInfo),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromSmoothy
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromSmoothy(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(int128 takerTokenIdx, SmoothyInfo memory smoothyInfo) =
|
||||
abi.decode(takerTokenData, (int128, SmoothyInfo));
|
||||
(int128 makerTokenIdx) =
|
||||
abi.decode(makerTokenData, (int128));
|
||||
(bool success, bytes memory resultData) =
|
||||
address(this).staticcall(abi.encodeWithSelector(
|
||||
this.sampleSellsFromSmoothy.selector,
|
||||
smoothyInfo,
|
||||
takerTokenIdx,
|
||||
makerTokenIdx,
|
||||
_toSingleValueArray(sellAmount)
|
||||
));
|
||||
if (!success) {
|
||||
return 0;
|
||||
}
|
||||
// solhint-disable-next-line indent
|
||||
return abi.decode(resultData, (uint256[]))[0];
|
||||
}
|
||||
}
|
@@ -1,412 +0,0 @@
|
||||
|
||||
|
||||
// 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 "./GasOverhead.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
|
||||
interface IHackedERC20 {
|
||||
function _setBalance(address owner, uint256 amount) external;
|
||||
function _setEnabled(bool enabled) external;
|
||||
}
|
||||
|
||||
contract SwapRevertSampler {
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
/// @dev Fixed address to register and read Gas overhead introduced by Swap revert sampling
|
||||
GasOverhead private constant GAS_OVERHEAD = GasOverhead(0xDeF1000000000000000000000000000000001337);
|
||||
/// @dev Maximum approximate (positive) error rate when approximating a buy quote.
|
||||
uint256 private constant APPROXIMATE_BUY_TARGET_EPSILON_BPS = 0.0005e4;
|
||||
/// @dev Maximum iterations to perform when approximating a buy quote.
|
||||
uint256 private constant APPROXIMATE_BUY_MAX_ITERATIONS = 3;
|
||||
uint256 private constant ONE_HUNDED_PERCENT_BPS = 1e4;
|
||||
/// @dev Upper limit of gas to give to a single Swap call
|
||||
uint256 private constant CALL_STIPEND = 2e6;
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
/// @dev Payable fallback to receive ETH from Kyber/WETH.
|
||||
receive ()
|
||||
external
|
||||
payable
|
||||
{ }
|
||||
|
||||
struct SwapRevertSamplerQuoteOpts {
|
||||
// Address of the token which is being sold
|
||||
address sellToken;
|
||||
// Address of the token which is wanted
|
||||
address buyToken;
|
||||
// Data required for the bridge to execute the swap
|
||||
bytes bridgeData;
|
||||
// Callback to retrieve a swap quote.
|
||||
function (address sellToken, address buyToken, bytes memory bridgeData, uint256 sellAmount)
|
||||
external
|
||||
returns (uint256)
|
||||
getSwapQuoteCallback;
|
||||
}
|
||||
|
||||
struct SwapRevertSamplerBuyQuoteOpts {
|
||||
// Address of the token which is being sold
|
||||
address sellToken;
|
||||
// Address of the token which is wanted
|
||||
address buyToken;
|
||||
// Data required for the bridge to execute the SELL_TOKEN->BUY_TOKEN swap
|
||||
bytes sellTokenData;
|
||||
// Data required for the bridge to execute the BUY_TOKEN->SELL_TOKEN swap
|
||||
bytes buyTokenData;
|
||||
// Callback to retrieve a swap quote.
|
||||
function (address sellToken, address buyToken, bytes memory bridgeData, uint256 sellAmount)
|
||||
external
|
||||
returns (uint256)
|
||||
getSwapQuoteCallback;
|
||||
}
|
||||
|
||||
function _callRevert(
|
||||
bytes4 selector,
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 amountIn
|
||||
)
|
||||
external
|
||||
{
|
||||
// Clear any registered overhead
|
||||
try
|
||||
GAS_OVERHEAD.clearOverhead()
|
||||
{ } catch { }
|
||||
// Measure the gas
|
||||
uint256 gasUsed = gasleft();
|
||||
// Perform the sell
|
||||
(bool success, bytes memory data) = address(this).call(
|
||||
abi.encodeWithSelector(selector, sellToken, buyToken, bridgeData, amountIn)
|
||||
);
|
||||
gasUsed = gasUsed - gasleft();
|
||||
// Remove any registered gas overhead
|
||||
try
|
||||
GAS_OVERHEAD.overhead()
|
||||
returns (uint256 gasOverhead)
|
||||
{
|
||||
gasUsed = gasUsed - gasOverhead;
|
||||
} catch { }
|
||||
|
||||
if (!success) {
|
||||
data.rrevert();
|
||||
}
|
||||
// Revert with the amount bought
|
||||
_revertSingleSwapSample(abi.decode(data, (uint256)), gasUsed);
|
||||
}
|
||||
|
||||
/// @dev Mints the sell token, then performs the swap, then reverts with the amount out.
|
||||
/// The SwapRevertSamplerQuoteOpts has been unrolled here as our ABI encoder cannot support
|
||||
/// encoding the function
|
||||
function _mintCallRevert(
|
||||
bytes4 selector,
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256[] memory amountsIn
|
||||
)
|
||||
external
|
||||
{
|
||||
// We assume the amounts are ascending and that
|
||||
// the underlying call can handle selling a specific amount
|
||||
uint256 amountIn = amountsIn[amountsIn.length - 1];
|
||||
|
||||
if (sellToken == address(_getNativeWrappedToken())) {
|
||||
try
|
||||
IEtherTokenV06(payable(sellToken)).deposit{ value: amountIn }()
|
||||
{ } catch { }
|
||||
} else {
|
||||
IHackedERC20 hackedSellToken = IHackedERC20(payable(sellToken));
|
||||
// Enable sell token to be tracked and shadowed
|
||||
try
|
||||
hackedSellToken._setEnabled(true)
|
||||
{ } catch { }
|
||||
|
||||
// Mint enough to sell
|
||||
try
|
||||
hackedSellToken._setBalance(address(this), amountIn)
|
||||
{ } catch { }
|
||||
}
|
||||
|
||||
// Burn any excess ETH to avoid balance issues for sources which use ETH directly
|
||||
address(0).transfer(address(this).balance);
|
||||
|
||||
uint256[] memory amountsOut = new uint256[](amountsIn.length);
|
||||
uint256[] memory gasUsed = new uint256[](amountsIn.length);
|
||||
|
||||
for (uint256 i = 0; i < amountsIn.length; i++) {
|
||||
try
|
||||
this._callRevert{gas: CALL_STIPEND}(
|
||||
selector,
|
||||
sellToken,
|
||||
buyToken,
|
||||
bridgeData,
|
||||
amountsIn[i]
|
||||
)
|
||||
{
|
||||
require(false, "Swap Sample should have reverted");
|
||||
} catch (bytes memory reason) {
|
||||
// Parse the reverted sample data
|
||||
(amountsOut[i], gasUsed[i]) = _parseRevertedSingleSwapSample(reason);
|
||||
// If we detect the amount out is 0 then we return early
|
||||
// rather than continue performing excess work
|
||||
|
||||
// Some sources (Balancer) display issues, especially with small amounts
|
||||
// Where the amountsOut can range, e.g 448,0,0,0,2476,3048,0,4279,4941,0,0,7133,
|
||||
|
||||
if (amountsOut[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Revert the entire sampling
|
||||
_revertSwapSample(amountsOut, gasUsed);
|
||||
}
|
||||
|
||||
function _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts memory opts,
|
||||
uint256[] memory amountsIn
|
||||
)
|
||||
internal
|
||||
returns (uint256[] memory gasUsed, uint256[] memory amountsOut)
|
||||
{
|
||||
try
|
||||
this._mintCallRevert(
|
||||
opts.getSwapQuoteCallback.selector,
|
||||
opts.sellToken,
|
||||
opts.buyToken,
|
||||
opts.bridgeData,
|
||||
amountsIn
|
||||
)
|
||||
{
|
||||
require(false, "Swap Sample should have reverted");
|
||||
} catch (bytes memory reason) {
|
||||
// Parse the reverted sample datas
|
||||
(amountsOut, gasUsed) = abi.decode(reason, (uint256[], uint256[]));
|
||||
}
|
||||
}
|
||||
|
||||
function _getNativeWrappedToken()
|
||||
internal
|
||||
view
|
||||
returns (IEtherTokenV06)
|
||||
{
|
||||
uint256 chainId;
|
||||
assembly {
|
||||
chainId := chainid()
|
||||
}
|
||||
address token;
|
||||
if (chainId == 1) {
|
||||
// Ethereum Mainnet
|
||||
token = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
} else if (chainId == 3) {
|
||||
// Ropsten
|
||||
token = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
|
||||
} else if (chainId == 4) {
|
||||
// Rinkeby
|
||||
token = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
|
||||
} else if (chainId == 42) {
|
||||
// Kovan
|
||||
token = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;
|
||||
} else if (chainId == 56) {
|
||||
// BSC
|
||||
token = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
|
||||
} else if (chainId == 137) {
|
||||
// Polygon
|
||||
token = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270;
|
||||
} else if (chainId == 1337) {
|
||||
// 0x Ganache
|
||||
token = 0x0B1ba0af832d7C05fD64161E0Db78E85978E8082;
|
||||
}
|
||||
if (token == address(0)) {
|
||||
revert("No native wrapped token");
|
||||
}
|
||||
return IEtherTokenV06(token);
|
||||
}
|
||||
|
||||
function _revertSingleSwapSample(
|
||||
uint256 amount,
|
||||
uint256 gasUsed
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Revert it so there is no state change
|
||||
assembly {
|
||||
mstore(0, amount)
|
||||
mstore(32, gasUsed)
|
||||
revert(0, 64)
|
||||
}
|
||||
}
|
||||
|
||||
function _revertSwapSample(
|
||||
uint256[] memory amounts,
|
||||
uint256[] memory gasUsed
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory data = abi.encode(amounts, gasUsed);
|
||||
// Revert it so there is no state change
|
||||
assembly {
|
||||
revert(add(data, 32), mload(data))
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Parses the reverted swap sample data. If no amount
|
||||
/// is decoded, 0 is returned.
|
||||
/// @param reason the string which contains the possible
|
||||
/// sample amount
|
||||
/// @return the decoded sample amount or 0
|
||||
/// @return the gas used in the sample
|
||||
function _parseRevertedSingleSwapSample(
|
||||
bytes memory reason
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256, uint256)
|
||||
{
|
||||
if (reason.length != 64) {
|
||||
return (0,0);
|
||||
}
|
||||
return abi.decode(reason, (uint256, uint256));
|
||||
}
|
||||
|
||||
function _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts memory opts,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
internal
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
if (makerTokenAmounts.length == 0) {
|
||||
return (gasUsed, takerTokenAmounts);
|
||||
}
|
||||
|
||||
takerTokenAmounts = new uint256[](makerTokenAmounts.length);
|
||||
gasUsed = new uint256[](makerTokenAmounts.length);
|
||||
|
||||
uint256[] memory sellAmounts = new uint256[](1);
|
||||
sellAmounts[0] = makerTokenAmounts[0];
|
||||
|
||||
SwapRevertSamplerQuoteOpts memory sellOpts = SwapRevertSamplerQuoteOpts({
|
||||
sellToken: opts.sellToken,
|
||||
buyToken: opts.buyToken,
|
||||
bridgeData: opts.sellTokenData,
|
||||
getSwapQuoteCallback: opts.getSwapQuoteCallback
|
||||
});
|
||||
|
||||
SwapRevertSamplerQuoteOpts memory buyOpts = SwapRevertSamplerQuoteOpts({
|
||||
sellToken: opts.buyToken,
|
||||
buyToken: opts.sellToken,
|
||||
bridgeData: opts.buyTokenData,
|
||||
getSwapQuoteCallback: opts.getSwapQuoteCallback
|
||||
});
|
||||
// Inverted, perform a sell of the token the user wants to buy
|
||||
(, sellAmounts) = _sampleSwapQuotesRevert(buyOpts, sellAmounts);
|
||||
if (sellAmounts.length == 0 || sellAmounts[0] == 0) {
|
||||
return (gasUsed, takerTokenAmounts);
|
||||
}
|
||||
|
||||
uint256[] memory buyAmounts;
|
||||
// Sell of the token the user wishes to dispose, see how much we buy
|
||||
(, buyAmounts) = _sampleSwapQuotesRevert(sellOpts, sellAmounts);
|
||||
|
||||
if (buyAmounts.length == 0 || buyAmounts[0] == 0) {
|
||||
return (gasUsed, takerTokenAmounts);
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < makerTokenAmounts.length; i++) {
|
||||
uint256[] memory _gasUsed;
|
||||
for (uint256 iter = 0; iter < APPROXIMATE_BUY_MAX_ITERATIONS; iter++) {
|
||||
// adjustedSellAmount = previousSellAmount * (target/actual) * JUMP_MULTIPLIER
|
||||
sellAmounts[0] = _safeGetPartialAmountCeil(
|
||||
makerTokenAmounts[i],
|
||||
buyAmounts[0],
|
||||
sellAmounts[0]
|
||||
);
|
||||
if (sellAmounts.length == 0 || sellAmounts[0] == 0) {
|
||||
break;
|
||||
}
|
||||
sellAmounts[0] = _safeGetPartialAmountCeil(
|
||||
(ONE_HUNDED_PERCENT_BPS + APPROXIMATE_BUY_TARGET_EPSILON_BPS),
|
||||
ONE_HUNDED_PERCENT_BPS,
|
||||
sellAmounts[0]
|
||||
);
|
||||
if (sellAmounts.length == 0 || sellAmounts[0] == 0) {
|
||||
break;
|
||||
}
|
||||
uint256[] memory _buyAmounts;
|
||||
(_gasUsed, _buyAmounts) = _sampleSwapQuotesRevert(sellOpts, sellAmounts);
|
||||
if (_buyAmounts.length == 0 || _buyAmounts[0] == 0) {
|
||||
break;
|
||||
}
|
||||
// We re-use buyAmount next iteration, only assign if it is
|
||||
// non zero
|
||||
buyAmounts = _buyAmounts;
|
||||
// If we've reached our goal, exit early
|
||||
if (buyAmounts[0] >= makerTokenAmounts[i]) {
|
||||
uint256 eps =
|
||||
(buyAmounts[0] - makerTokenAmounts[i]) * ONE_HUNDED_PERCENT_BPS /
|
||||
makerTokenAmounts[i];
|
||||
if (eps <= APPROXIMATE_BUY_TARGET_EPSILON_BPS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We've encountered reverts, so bail
|
||||
if (_gasUsed.length == 0 || _gasUsed[0] == 0) {
|
||||
return (gasUsed, takerTokenAmounts);
|
||||
}
|
||||
|
||||
if (buyAmounts.length > 0) {
|
||||
gasUsed[i] = _gasUsed[0];
|
||||
// We do our best to close in on the requested amount, but we can either over buy or under buy and exit
|
||||
// if we hit a max iteration limit
|
||||
// We scale the sell amount to get the approximate target
|
||||
takerTokenAmounts[i] = _safeGetPartialAmountCeil(
|
||||
makerTokenAmounts[i],
|
||||
buyAmounts[0],
|
||||
sellAmounts[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _safeGetPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
if (numerator == 0 || target == 0 || denominator == 0) return 0;
|
||||
uint256 c = numerator * target;
|
||||
if (c / numerator != target) return 0;
|
||||
return (c + (denominator - 1)) / denominator;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -40,11 +40,10 @@ contract TwoHopSampler {
|
||||
returns (
|
||||
HopInfo memory firstHop,
|
||||
HopInfo memory secondHop,
|
||||
uint256 intermediateAssetAmount,
|
||||
uint256 buyAmount
|
||||
)
|
||||
{
|
||||
intermediateAssetAmount = 0;
|
||||
uint256 intermediateAssetAmount = 0;
|
||||
for (uint256 i = 0; i != firstHopCalls.length; ++i) {
|
||||
firstHopCalls[i].writeUint256(firstHopCalls[i].length - 32, sellAmount);
|
||||
(bool didSucceed, bytes memory returnData) = address(this).call(firstHopCalls[i]);
|
||||
@@ -58,7 +57,7 @@ contract TwoHopSampler {
|
||||
}
|
||||
}
|
||||
if (intermediateAssetAmount == 0) {
|
||||
return (firstHop, secondHop, intermediateAssetAmount, buyAmount);
|
||||
return (firstHop, secondHop, buyAmount);
|
||||
}
|
||||
for (uint256 j = 0; j != secondHopCalls.length; ++j) {
|
||||
secondHopCalls[j].writeUint256(secondHopCalls[j].length - 32, intermediateAssetAmount);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,43 +20,32 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswap.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
import "./interfaces/IUniswapExchangeQuotes.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
interface IUniswapExchangeFactory {
|
||||
|
||||
/// @dev Get the exchange for a token.
|
||||
/// @param tokenAddress The address of the token contract.
|
||||
function getExchange(address tokenAddress)
|
||||
external
|
||||
view
|
||||
returns (address);
|
||||
}
|
||||
|
||||
|
||||
contract UniswapSampler is
|
||||
MixinUniswap,
|
||||
SwapRevertSampler
|
||||
SamplerUtils
|
||||
{
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinUniswap(weth)
|
||||
{ }
|
||||
|
||||
function sampleSwapFromUniswap(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeUniswapInternal(
|
||||
_getNativeWrappedToken(),
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Gas limit for Uniswap calls.
|
||||
uint256 constant private UNISWAP_CALL_GAS = 150e3; // 150k
|
||||
|
||||
/// @dev Sample sell quotes from Uniswap.
|
||||
/// @param router Address of the Uniswap Router
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromUniswap(
|
||||
@@ -66,24 +55,59 @@ contract UniswapSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswap
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == address(0) ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(router, takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == address(0) ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(router, makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
bool didSucceed = true;
|
||||
if (makerToken == address(0)) {
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == address(0)) {
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethBought;
|
||||
(ethBought, didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
if (ethBought != 0) {
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
ethBought
|
||||
);
|
||||
} else {
|
||||
makerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
// Break early if amounts are 0
|
||||
if (!didSucceed || makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Uniswap.
|
||||
/// @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 gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromUniswap(
|
||||
@@ -93,18 +117,98 @@ contract UniswapSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(router),
|
||||
buyTokenData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswap
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == address(0) ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(router, takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == address(0) ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(router, makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
bool didSucceed = true;
|
||||
if (makerToken == address(0)) {
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == address(0)) {
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethSold;
|
||||
(ethSold, didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
if (ethSold != 0) {
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
ethSold
|
||||
);
|
||||
} else {
|
||||
takerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
// Break early if amounts are 0
|
||||
if (!didSucceed || takerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Gracefully calls a Uniswap pricing function.
|
||||
/// @param uniswapExchangeAddress Address of an `IUniswapExchangeQuotes` exchange.
|
||||
/// @param functionSelector Selector of the target function.
|
||||
/// @param inputAmount Quantity parameter particular to the pricing function.
|
||||
/// @return outputAmount The returned amount from the function call. Will be
|
||||
/// zero if the call fails or if `uniswapExchangeAddress` is zero.
|
||||
function _callUniswapExchangePriceFunction(
|
||||
address uniswapExchangeAddress,
|
||||
bytes4 functionSelector,
|
||||
uint256 inputAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 outputAmount, bool didSucceed)
|
||||
{
|
||||
if (uniswapExchangeAddress == address(0)) {
|
||||
return (outputAmount, didSucceed);
|
||||
}
|
||||
bytes memory resultData;
|
||||
(didSucceed, resultData) =
|
||||
uniswapExchangeAddress.staticcall.gas(UNISWAP_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
functionSelector,
|
||||
inputAmount
|
||||
));
|
||||
if (didSucceed) {
|
||||
outputAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrive an existing Uniswap exchange contract.
|
||||
/// Throws if the exchange does not exist.
|
||||
/// @param router Address of the Uniswap router.
|
||||
/// @param tokenAddress Address of the token contract.
|
||||
/// @return exchange `IUniswapExchangeQuotes` for the token.
|
||||
function _getUniswapExchange(address router, address tokenAddress)
|
||||
private
|
||||
view
|
||||
returns (IUniswapExchangeQuotes exchange)
|
||||
{
|
||||
exchange = IUniswapExchangeQuotes(
|
||||
address(IUniswapExchangeFactory(router)
|
||||
.getExchange(tokenAddress))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,36 +21,17 @@ pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IUniswapV2Router01.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswapV2.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
|
||||
contract UniswapV2Sampler is
|
||||
MixinUniswapV2,
|
||||
SwapRevertSampler
|
||||
contract UniswapV2Sampler
|
||||
{
|
||||
|
||||
function sampleSwapFromUniswapV2(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeUniswapV2(
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
/// @dev Gas limit for UniswapV2 calls.
|
||||
uint256 constant private UNISWAPV2_CALL_GAS = 150e3; // 150k
|
||||
|
||||
/// @dev Sample sell quotes from UniswapV2.
|
||||
/// @param router Router to look up tokens and amounts
|
||||
/// @param path Token route. Should be takerToken -> makerToken
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return gasUsed gas consumed for each sample amount
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromUniswapV2(
|
||||
@@ -59,24 +40,34 @@ contract UniswapV2Sampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: path[0],
|
||||
buyToken: path[path.length - 1],
|
||||
bridgeData: abi.encode(router, path),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswapV2
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IUniswapV2Router01(router).getAmountsOut
|
||||
{gas: UNISWAPV2_CALL_GAS}
|
||||
(takerTokenAmounts[i], path)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
makerTokenAmounts[i] = amounts[path.length - 1];
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from UniswapV2.
|
||||
/// @param router Router to look up tokens and amounts
|
||||
/// @param path Token route. Should be takerToken -> makerToken.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return gasUsed gas consumed for each sample amount
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromUniswapV2(
|
||||
@@ -85,22 +76,27 @@ contract UniswapV2Sampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
address[] memory reversedPath = new address[](path.length);
|
||||
for (uint256 i = 0; i < path.length; ++i) {
|
||||
reversedPath[i] = path[path.length - i - 1];
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
try
|
||||
IUniswapV2Router01(router).getAmountsIn
|
||||
{gas: UNISWAPV2_CALL_GAS}
|
||||
(makerTokenAmounts[i], path)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
takerTokenAmounts[i] = amounts[0];
|
||||
// Break early if there are 0 amounts
|
||||
if (takerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: path[0],
|
||||
buyToken: path[path.length - 1],
|
||||
sellTokenData: abi.encode(router, path),
|
||||
buyTokenData: abi.encode(router, reversedPath),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswapV2
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user