Compare commits
22 Commits
@0x/protoc
...
poc/rust-r
Author | SHA1 | Date | |
---|---|---|---|
|
292ce6ea84 | ||
|
7972c2ce4e | ||
|
173d4ce648 | ||
|
59542f0585 | ||
|
446ef9660e | ||
|
9de1f0263a | ||
|
835ee4e8de | ||
|
63ec42303f | ||
|
f789aebddc | ||
|
efd83be779 | ||
|
603bc1d51c | ||
|
32a930a7fc | ||
|
f464bf68d7 | ||
|
ebdc4fb509 | ||
|
7580719586 | ||
|
aba9db2be7 | ||
|
a6680411c8 | ||
|
0d0e87de94 | ||
|
ccf2000c09 | ||
|
3eb2e0f56a | ||
|
d07c7d5b69 | ||
|
adf6684c29 |
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.7.16",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "3.7.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "3.7.14",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.7.16 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.15 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.14 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.7.14",
|
||||
"version": "3.7.16",
|
||||
"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.0",
|
||||
"@0x/contract-wrappers": "^13.17.2",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@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.32",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-erc721": "^3.1.32",
|
||||
"@0x/contracts-exchange-libs": "^4.3.32",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@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/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "1.1.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "1.1.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "1.1.32",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.33 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.32 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-broker",
|
||||
"version": "1.1.32",
|
||||
"version": "1.1.34",
|
||||
"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.14",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-erc721": "^3.1.32",
|
||||
"@0x/contracts-exchange": "^3.2.33",
|
||||
"@0x/contracts-exchange-libs": "^4.3.32",
|
||||
"@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-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@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.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"ethereum-types": "^3.5.0"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.1.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "3.1.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "3.1.33",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.34 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.33 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.1.33",
|
||||
"version": "3.1.35",
|
||||
"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.14",
|
||||
"@0x/contracts-dev-utils": "^1.3.31",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-dev-utils": "^1.3.33",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@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.3.0",
|
||||
"@0x/contracts-exchange": "^3.2.33",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@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/json-schemas": "^6.1.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "1.3.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "1.3.32",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "1.3.31",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.3.33 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.32 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.31 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.3.31",
|
||||
"version": "1.3.33",
|
||||
"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.14",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "2.1.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "2.1.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "2.1.32",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.1.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.33 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.32 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.1.32",
|
||||
"version": "2.1.34",
|
||||
"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.11",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@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.3",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"lodash": "^4.17.11"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.3.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "3.3.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "3.3.11",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.3.13 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.12 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.11 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.3.11",
|
||||
"version": "3.3.13",
|
||||
"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.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.1.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "3.1.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "3.1.32",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.33 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.32 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.1.32",
|
||||
"version": "3.1.34",
|
||||
"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.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.2.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "4.2.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "4.2.33",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.34 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.33 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.2.33",
|
||||
"version": "4.2.35",
|
||||
"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.14",
|
||||
"@0x/contracts-dev-utils": "^1.3.31",
|
||||
"@0x/contracts-erc1155": "^2.1.32",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-erc721": "^3.1.32",
|
||||
"@0x/contracts-exchange": "^3.2.33",
|
||||
"@0x/contracts-exchange-libs": "^4.3.32",
|
||||
"@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-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.3.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "4.3.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "4.3.32",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.3.34 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.33 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.32 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.3.32",
|
||||
"version": "4.3.34",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -81,9 +81,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "3.2.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "3.2.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "3.2.33",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.34 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.33 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.2.33",
|
||||
"version": "3.2.35",
|
||||
"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.14",
|
||||
"@0x/contracts-exchange-libs": "^4.3.32",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-exchange-libs": "^4.3.34",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-multisig": "^4.1.33",
|
||||
"@0x/contracts-staking": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@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/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.31",
|
||||
"@0x/contracts-erc1155": "^2.1.32",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-erc721": "^3.1.32",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@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/utils": "^6.4.3",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "6.2.29",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "6.2.28",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "6.2.27",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.2.29 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.2.28 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.2.27 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "6.2.27",
|
||||
"version": "6.2.29",
|
||||
"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.14",
|
||||
"@0x/contracts-dev-utils": "^1.3.31",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-erc721": "^3.1.32",
|
||||
"@0x/contracts-exchange": "^3.2.33",
|
||||
"@0x/contracts-exchange-libs": "^4.3.32",
|
||||
"@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-gen": "^2.0.38",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@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.3",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"ethereum-types": "^3.5.0"
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-integrations",
|
||||
"version": "2.7.48",
|
||||
"version": "2.7.53",
|
||||
"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.3.0",
|
||||
"@0x/contract-wrappers": "^13.17.0",
|
||||
"@0x/contracts-broker": "^1.1.32",
|
||||
"@0x/contracts-coordinator": "^3.1.33",
|
||||
"@0x/contracts-dev-utils": "^1.3.31",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.33",
|
||||
"@0x/contracts-exchange-libs": "^4.3.32",
|
||||
"@0x/contracts-extensions": "^6.2.27",
|
||||
"@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/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/coordinator-server": "^1.0.5",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/migrations": "^8.0.9",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/protocol-utils": "^1.7.0",
|
||||
"@0x/migrations": "^8.0.11",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/protocol-utils": "^1.7.2",
|
||||
"@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.17.1",
|
||||
"@0x/asset-swapper": "^6.18.2",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.14",
|
||||
"@0x/contracts-erc1155": "^2.1.32",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-erc721": "^3.1.32",
|
||||
"@0x/contracts-exchange": "^3.2.33",
|
||||
"@0x/contracts-multisig": "^4.1.33",
|
||||
"@0x/contracts-staking": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-zero-ex": "^0.25.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/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.1.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "4.1.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "4.1.33",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.35 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.34 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.33 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-multisig",
|
||||
"version": "4.1.33",
|
||||
"version": "4.1.35",
|
||||
"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.14",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "2.0.42",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "2.0.41",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "2.0.40",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.42 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.41 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.40 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-staking",
|
||||
"version": "2.0.40",
|
||||
"version": "2.0.42",
|
||||
"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.14",
|
||||
"@0x/contracts-dev-utils": "^1.3.31",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contracts-exchange-libs": "^4.3.32",
|
||||
"@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-gen": "^2.0.38",
|
||||
"@0x/contracts-utils": "^4.7.11",
|
||||
"@0x/contracts-utils": "^4.7.13",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@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.3",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"ethereum-types": "^3.5.0",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "5.4.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "5.4.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "5.4.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.4.5 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.4 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.3 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.4.3",
|
||||
"version": "5.4.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,10 +44,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.3.0",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/json-schemas": "^6.1.3",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/sol-coverage": "^4.0.37",
|
||||
"@0x/sol-profiler": "^4.1.27",
|
||||
"@0x/sol-trace": "^3.0.37",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "1.2.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "1.2.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "1.2.1",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.2.3 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.2.2 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.2.1 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-treasury",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.3",
|
||||
"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.3.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.14",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.16",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-staking": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-staking": "^2.0.42",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@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.0",
|
||||
"@0x/protocol-utils": "^1.7.2",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1624356181,
|
||||
"version": "4.7.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "4.7.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "4.7.11",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.7.13 - _June 22, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.7.12 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.7.11 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.7.11",
|
||||
"version": "4.7.13",
|
||||
"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.3",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.3",
|
||||
|
@@ -1,4 +1,32 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.26.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add Lido stETH deposit integration",
|
||||
"pr": 260
|
||||
}
|
||||
],
|
||||
"timestamp": 1624356181
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "0.25.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.25.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.26.0 - _June 22, 2021_
|
||||
|
||||
* Add Lido stETH deposit integration (#260)
|
||||
|
||||
## v0.25.1 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.25.0 - _June 2, 2021_
|
||||
|
||||
* Add OtcOrdersFeature (#244)
|
||||
|
@@ -27,11 +27,13 @@ import "./mixins/MixinBalancerV2.sol";
|
||||
import "./mixins/MixinBancor.sol";
|
||||
import "./mixins/MixinCoFiX.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
import "./mixins/MixinCryptoCom.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyber.sol";
|
||||
import "./mixins/MixinKyberDmm.sol";
|
||||
import "./mixins/MixinLido.sol";
|
||||
import "./mixins/MixinMakerPSM.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
import "./mixins/MixinMStable.sol";
|
||||
@@ -50,11 +52,13 @@ contract BridgeAdapter is
|
||||
MixinBancor,
|
||||
MixinCoFiX,
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
MixinCryptoCom,
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyber,
|
||||
MixinKyberDmm,
|
||||
MixinLido,
|
||||
MixinMakerPSM,
|
||||
MixinMooniswap,
|
||||
MixinMStable,
|
||||
@@ -73,10 +77,12 @@ contract BridgeAdapter is
|
||||
MixinBancor(weth)
|
||||
MixinCoFiX()
|
||||
MixinCurve(weth)
|
||||
MixinCurveV2()
|
||||
MixinCryptoCom()
|
||||
MixinDodo()
|
||||
MixinDodoV2()
|
||||
MixinKyber(weth)
|
||||
MixinLido(weth)
|
||||
MixinMakerPSM()
|
||||
MixinMooniswap(weth)
|
||||
MixinMStable()
|
||||
@@ -107,6 +113,13 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CURVEV2) {
|
||||
boughtAmount = _tradeCurveV2(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.UNISWAPV3) {
|
||||
boughtAmount = _tradeUniswapV3(
|
||||
sellToken,
|
||||
@@ -225,6 +238,13 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.LIDO) {
|
||||
boughtAmount = _tradeLido(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
|
@@ -47,4 +47,6 @@ library BridgeProtocols {
|
||||
uint128 internal constant BALANCERV2 = 17;
|
||||
uint128 internal constant UNISWAPV3 = 18;
|
||||
uint128 internal constant KYBERDMM = 19;
|
||||
uint128 internal constant CURVEV2 = 20;
|
||||
uint128 internal constant LIDO = 21;
|
||||
}
|
||||
|
@@ -39,6 +39,13 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +69,18 @@ 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;
|
||||
@@ -79,7 +98,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"
|
||||
);
|
||||
|
||||
@@ -88,7 +107,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.
|
||||
@@ -109,7 +128,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;
|
||||
|
@@ -57,13 +57,26 @@ 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);
|
||||
}
|
||||
@@ -83,9 +96,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);
|
||||
|
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
|
||||
contract MixinCurveV2 {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
struct CurveBridgeDataV2 {
|
||||
address curveAddress;
|
||||
bytes4 exchangeFunctionSelector;
|
||||
int128 fromCoinIdx;
|
||||
int128 toCoinIdx;
|
||||
}
|
||||
|
||||
function _tradeCurveV2(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data to get the Curve metadata.
|
||||
CurveBridgeDataV2 memory data = abi.decode(bridgeData, (CurveBridgeDataV2));
|
||||
sellToken.approveIfBelow(data.curveAddress, sellAmount);
|
||||
|
||||
uint256 beforeBalance = buyToken.balanceOf(address(this));
|
||||
(bool success, bytes memory resultData) =
|
||||
data.curveAddress.call(abi.encodeWithSelector(
|
||||
data.exchangeFunctionSelector,
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
sellAmount,
|
||||
// min dy
|
||||
1
|
||||
));
|
||||
if (!success) {
|
||||
resultData.rrevert();
|
||||
}
|
||||
|
||||
return buyToken.balanceOf(address(this)).safeSub(beforeBalance);
|
||||
}
|
||||
}
|
@@ -52,6 +52,7 @@ interface IKyberNetworkProxy {
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount);
|
||||
|
||||
}
|
||||
|
||||
contract MixinKyber {
|
||||
@@ -78,12 +79,26 @@ 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(
|
||||
@@ -93,18 +108,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 ? KYBER_ETH_ADDRESS : sellToken,
|
||||
sellToken == weth ? kyberEthAddress : sellToken,
|
||||
// Sell amount.
|
||||
sellAmount,
|
||||
// Output token.
|
||||
buyToken == WETH ? KYBER_ETH_ADDRESS : buyToken,
|
||||
buyToken == weth ? kyberEthAddress : buyToken,
|
||||
// Transfer to this contract
|
||||
address(uint160(address(this))),
|
||||
// Buy as much as possible.
|
||||
@@ -116,8 +131,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,6 +30,8 @@ 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).
|
||||
|
@@ -0,0 +1,83 @@
|
||||
// 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";
|
||||
|
||||
|
||||
/// @dev Minimal interface for minting StETH
|
||||
interface ILido {
|
||||
/// @dev Adds eth to the pool
|
||||
/// @param _referral optional address for referrals
|
||||
/// @return StETH Amount of shares generated
|
||||
function submit(address _referral) external payable returns (uint256 StETH);
|
||||
/// @dev Retrieve the current pooled ETH representation of the shares amount
|
||||
/// @param _sharesAmount amount of shares
|
||||
/// @return amount of pooled ETH represented by the shares amount
|
||||
function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract MixinLido {
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibERC20TokenV06 for IEtherTokenV06;
|
||||
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
{
|
||||
WETH = weth;
|
||||
}
|
||||
|
||||
function _tradeLido(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
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);
|
||||
boughtAmount = lido.getPooledEthByShares(lido.submit{ value: sellAmount}(address(0)));
|
||||
} else {
|
||||
revert("MixinLido/UNSUPPORTED_TOKEN_PAIR");
|
||||
}
|
||||
}
|
||||
}
|
@@ -66,12 +66,26 @@ 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.
|
||||
@@ -82,16 +96,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,21 +124,35 @@ 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.
|
||||
@@ -150,7 +164,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),
|
||||
@@ -166,7 +180,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.
|
||||
@@ -200,6 +214,7 @@ 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
|
||||
@@ -209,7 +224,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.25.0",
|
||||
"version": "0.26.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|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|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|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.3.0",
|
||||
"@0x/contracts-erc20": "^3.3.11",
|
||||
"@0x/contract-addresses": "^6.4.0",
|
||||
"@0x/contracts-erc20": "^3.3.13",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.3",
|
||||
"@0x/contracts-test-utils": "^5.4.5",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/order-utils": "^10.4.24",
|
||||
"@0x/order-utils": "^10.4.26",
|
||||
"@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.0",
|
||||
"@0x/protocol-utils": "^1.7.2",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
|
@@ -85,10 +85,12 @@ import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
|
||||
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
|
||||
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
|
||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||
import * as MixinCurveV2 from '../test/generated-artifacts/MixinCurveV2.json';
|
||||
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
|
||||
import * as MixinDodoV2 from '../test/generated-artifacts/MixinDodoV2.json';
|
||||
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
|
||||
import * as MixinKyberDmm from '../test/generated-artifacts/MixinKyberDmm.json';
|
||||
import * as MixinLido from '../test/generated-artifacts/MixinLido.json';
|
||||
import * as MixinMakerPSM from '../test/generated-artifacts/MixinMakerPSM.json';
|
||||
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
|
||||
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
|
||||
@@ -258,10 +260,12 @@ export const artifacts = {
|
||||
MixinCoFiX: MixinCoFiX as ContractArtifact,
|
||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
MixinCurveV2: MixinCurveV2 as ContractArtifact,
|
||||
MixinDodo: MixinDodo as ContractArtifact,
|
||||
MixinDodoV2: MixinDodoV2 as ContractArtifact,
|
||||
MixinKyber: MixinKyber as ContractArtifact,
|
||||
MixinKyberDmm: MixinKyberDmm as ContractArtifact,
|
||||
MixinLido: MixinLido as ContractArtifact,
|
||||
MixinMStable: MixinMStable as ContractArtifact,
|
||||
MixinMakerPSM: MixinMakerPSM as ContractArtifact,
|
||||
MixinMooniswap: MixinMooniswap as ContractArtifact,
|
||||
|
@@ -83,10 +83,12 @@ export * from '../test/generated-wrappers/mixin_bancor';
|
||||
export * from '../test/generated-wrappers/mixin_co_fi_x';
|
||||
export * from '../test/generated-wrappers/mixin_crypto_com';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
export * from '../test/generated-wrappers/mixin_curve_v2';
|
||||
export * from '../test/generated-wrappers/mixin_dodo';
|
||||
export * from '../test/generated-wrappers/mixin_dodo_v2';
|
||||
export * from '../test/generated-wrappers/mixin_kyber';
|
||||
export * from '../test/generated-wrappers/mixin_kyber_dmm';
|
||||
export * from '../test/generated-wrappers/mixin_lido';
|
||||
export * from '../test/generated-wrappers/mixin_m_stable';
|
||||
export * from '../test/generated-wrappers/mixin_maker_p_s_m';
|
||||
export * from '../test/generated-wrappers/mixin_mooniswap';
|
||||
|
@@ -116,10 +116,12 @@
|
||||
"test/generated-artifacts/MixinCoFiX.json",
|
||||
"test/generated-artifacts/MixinCryptoCom.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
"test/generated-artifacts/MixinCurveV2.json",
|
||||
"test/generated-artifacts/MixinDodo.json",
|
||||
"test/generated-artifacts/MixinDodoV2.json",
|
||||
"test/generated-artifacts/MixinKyber.json",
|
||||
"test/generated-artifacts/MixinKyberDmm.json",
|
||||
"test/generated-artifacts/MixinLido.json",
|
||||
"test/generated-artifacts/MixinMStable.json",
|
||||
"test/generated-artifacts/MixinMakerPSM.json",
|
||||
"test/generated-artifacts/MixinMooniswap.json",
|
||||
|
@@ -1,4 +1,60 @@
|
||||
[
|
||||
{
|
||||
"version": "7.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "SwapRevertSampler. Refactored sampler to use exchange functions. Remove gas schedule.",
|
||||
"pr": 245
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1624562704,
|
||||
"version": "6.18.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "6.18.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "FirebirdOneSwap, ApeSwap. New hop tokens: DFYN, BANANA, WEXPOLY",
|
||||
"pr": 265
|
||||
}
|
||||
],
|
||||
"timestamp": 1624405040
|
||||
},
|
||||
{
|
||||
"version": "6.18.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add Lido stETH deposit integration",
|
||||
"pr": 260
|
||||
}
|
||||
],
|
||||
"timestamp": 1624356181
|
||||
},
|
||||
{
|
||||
"version": "6.17.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "QUICK, TITAN, IRON as intermediate tokens, integrating WaultSwap and Polydex for Polygon, Curve renBTC pool"
|
||||
}
|
||||
],
|
||||
"timestamp": 1623807529
|
||||
},
|
||||
{
|
||||
"timestamp": 1623382456,
|
||||
"version": "6.17.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1622609597,
|
||||
"version": "6.17.1",
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.18.2 - _June 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.18.1 - _June 22, 2021_
|
||||
|
||||
* FirebirdOneSwap, ApeSwap. New hop tokens: DFYN, BANANA, WEXPOLY (#265)
|
||||
|
||||
## v6.18.0 - _June 22, 2021_
|
||||
|
||||
* Add Lido stETH deposit integration (#260)
|
||||
|
||||
## v6.17.3 - _June 16, 2021_
|
||||
|
||||
* QUICK, TITAN, IRON as intermediate tokens, integrating WaultSwap and Polydex for Polygon, Curve renBTC pool
|
||||
|
||||
## v6.17.2 - _June 11, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.17.1 - _June 2, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,144 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@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 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -20,26 +20,29 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IBalancer.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinBalancer.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
contract BalancerSampler is
|
||||
MixinBalancer,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
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;
|
||||
function sampleSwapFromBalancer(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeBalancer(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Balancer.
|
||||
@@ -47,6 +50,7 @@ contract BalancerSampler {
|
||||
/// @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(
|
||||
@@ -56,52 +60,17 @@ contract BalancerSampler {
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(poolAddress),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancer
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Balancer.
|
||||
@@ -109,6 +78,7 @@ contract BalancerSampler {
|
||||
/// @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(
|
||||
@@ -118,74 +88,18 @@ contract BalancerSampler {
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
IBalancer pool = IBalancer(poolAddress);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
if (!pool.isBound(takerToken) || !pool.isBound(makerToken)) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(poolAddress),
|
||||
buyTokenData: abi.encode(poolAddress),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancer
|
||||
}),
|
||||
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#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,44 +20,29 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinBalancerV2.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
/// @dev Minimal Balancer V2 Vault interface
|
||||
/// for documentation refer to https://github.com/balancer-labs/balancer-core-v2/blob/master/contracts/vault/interfaces/IVault.sol
|
||||
interface IBalancerV2Vault {
|
||||
enum SwapKind { GIVEN_IN, GIVEN_OUT }
|
||||
contract BalancerV2Sampler is
|
||||
MixinBalancerV2,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
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;
|
||||
function sampleSwapFromBalancerV2(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeBalancerV2(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Balancer V2.
|
||||
@@ -65,48 +50,27 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
/// @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(
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
BalancerV2BridgeData memory poolInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||
IAsset[] memory swapAssets = new IAsset[](2);
|
||||
swapAssets[0] = IAsset(takerToken);
|
||||
swapAssets[1] = IAsset(makerToken);
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||
_createSwapFunds();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||
_createSwapSteps(poolInfo, takerTokenAmounts[i]);
|
||||
|
||||
try
|
||||
// For sells we specify the takerToken which is what the vault will receive from the trade
|
||||
vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_IN, swapSteps, swapAssets, swapFunds)
|
||||
// amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
|
||||
returns (int256[] memory amounts) {
|
||||
// Outgoing balance is negative so we need to flip the sign
|
||||
int256 amountOutFromPool = amounts[1] * -1;
|
||||
if (amountOutFromPool <= 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = uint256(amountOutFromPool);
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(poolInfo),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancerV2
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Balancer V2.
|
||||
@@ -114,76 +78,27 @@ contract BalancerV2Sampler is SamplerUtils {
|
||||
/// @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(
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
BalancerV2BridgeData memory poolInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||
IAsset[] memory swapAssets = new IAsset[](2);
|
||||
swapAssets[0] = IAsset(takerToken);
|
||||
swapAssets[1] = IAsset(makerToken);
|
||||
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||
_createSwapFunds();
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||
_createSwapSteps(poolInfo, makerTokenAmounts[i]);
|
||||
|
||||
try
|
||||
// For buys we specify the makerToken which is what taker will receive from the trade
|
||||
vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_OUT, swapSteps, swapAssets, swapFunds)
|
||||
returns (int256[] memory amounts) {
|
||||
int256 amountIntoPool = amounts[0];
|
||||
if (amountIntoPool <= 0) {
|
||||
break;
|
||||
}
|
||||
takerTokenAmounts[i] = uint256(amountIntoPool);
|
||||
} catch (bytes memory) {
|
||||
// Swallow failures, leaving all results as zero.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _createSwapSteps(
|
||||
BalancerV2PoolInfo memory poolInfo,
|
||||
uint256 amount
|
||||
) private pure returns (IBalancerV2Vault.BatchSwapStep[] memory) {
|
||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||
new IBalancerV2Vault.BatchSwapStep[](1);
|
||||
swapSteps[0] = IBalancerV2Vault.BatchSwapStep({
|
||||
poolId: poolInfo.poolId,
|
||||
assetInIndex: 0,
|
||||
assetOutIndex: 1,
|
||||
amount: amount,
|
||||
userData: ""
|
||||
});
|
||||
|
||||
return swapSteps;
|
||||
}
|
||||
|
||||
function _createSwapFunds()
|
||||
private
|
||||
view
|
||||
returns (IBalancerV2Vault.FundManagement memory)
|
||||
{
|
||||
return
|
||||
IBalancerV2Vault.FundManagement({
|
||||
sender: address(this),
|
||||
fromInternalBalance: false,
|
||||
recipient: payable(address(this)),
|
||||
toInternalBalance: false
|
||||
});
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(poolInfo),
|
||||
buyTokenData: abi.encode(poolInfo),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBalancerV2
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -20,11 +20,21 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IBancor.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinBancor.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
contract CompilerHack {}
|
||||
|
||||
contract BancorSampler is CompilerHack {
|
||||
contract BancorSampler is
|
||||
CompilerHack,
|
||||
MixinBancor,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
MixinBancor(weth)
|
||||
{ }
|
||||
|
||||
/// @dev Base gas limit for Bancor calls.
|
||||
uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k
|
||||
@@ -34,6 +44,23 @@ contract BancorSampler is CompilerHack {
|
||||
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).
|
||||
@@ -41,6 +68,7 @@ contract BancorSampler is CompilerHack {
|
||||
/// @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(
|
||||
@@ -50,34 +78,30 @@ contract BancorSampler is CompilerHack {
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (address bancorNetwork, address[] memory path, uint256[] memory makerTokenAmounts)
|
||||
returns (
|
||||
address bancorNetwork,
|
||||
address[] memory path,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
{
|
||||
if (opts.paths.length == 0) {
|
||||
return (bancorNetwork, path, makerTokenAmounts);
|
||||
return (bancorNetwork, path, gasUsed, makerTokenAmounts);
|
||||
}
|
||||
(bancorNetwork, path) = _findBestPath(opts, takerToken, makerToken, takerTokenAmounts);
|
||||
makerTokenAmounts = new uint256[](takerTokenAmounts.length);
|
||||
|
||||
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);
|
||||
(bancorNetwork, path) = _findBestPath(opts, takerToken, makerToken, takerTokenAmounts);
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(bancorNetwork, path),
|
||||
getSwapQuoteCallback: this.sampleSwapFromBancor
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
|
||||
return (bancorNetwork, path, gasUsed, makerTokenAmounts);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Bancor. Unimplemented
|
||||
@@ -87,6 +111,7 @@ contract BancorSampler is CompilerHack {
|
||||
/// @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(
|
||||
@@ -97,7 +122,7 @@ contract BancorSampler is CompilerHack {
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (address bancorNetwork, address[] memory path, uint256[] memory takerTokenAmounts)
|
||||
returns (address bancorNetwork, address[] memory path, uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -20,142 +20,99 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/ICurve.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinCurve.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
|
||||
contract CurveSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinCurve,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @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+
|
||||
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 Sample sell quotes from Curve.
|
||||
/// @param curveInfo Curve 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 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 sampleSellsFromCurve(
|
||||
CurveInfo memory curveInfo,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
CurveBridgeData memory curveInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(curveInfo),
|
||||
getSwapQuoteCallback: this.sampleSwapFromCurve
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Curve.
|
||||
/// @param curveInfo Curve 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 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 sampleBuysFromCurve(
|
||||
CurveInfo memory curveInfo,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
CurveBridgeData memory curveInfo,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
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];
|
||||
(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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
112
packages/asset-swapper/contracts/src/CurveV2Sampler.sol
Normal file
112
packages/asset-swapper/contracts/src/CurveV2Sampler.sol
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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,35 +20,40 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinDodo.sol";
|
||||
import "./SwapRevertSampler.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
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinDodo,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
/// @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).
|
||||
@@ -56,6 +61,7 @@ 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(
|
||||
@@ -65,13 +71,13 @@ contract DODOSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
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
|
||||
@@ -82,29 +88,21 @@ contract DODOSampler is
|
||||
pool = IDODOZoo(opts.registry).getDODO(makerToken, takerToken);
|
||||
// No pool either direction
|
||||
if (address(pool) == address(0)) {
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
return (sellBase, pool, gasUsed, makerTokenAmounts);
|
||||
}
|
||||
baseToken = makerToken;
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(opts.helper, pool, sellBase),
|
||||
getSwapQuoteCallback: this.sampleSwapFromDodo
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from DODO.
|
||||
@@ -114,6 +112,7 @@ 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(
|
||||
@@ -123,13 +122,13 @@ contract DODOSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
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);
|
||||
@@ -143,69 +142,21 @@ contract DODOSampler is
|
||||
pool = IDODOZoo(opts.registry).getDODO(makerToken, takerToken);
|
||||
// No pool either direction
|
||||
if (address(pool) == address(0)) {
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
return (sellBase, pool, gasUsed, takerTokenAmounts);
|
||||
}
|
||||
baseToken = makerToken;
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
// 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
|
||||
(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
|
||||
}),
|
||||
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 "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinDodoV2.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
interface IDODOV2Registry {
|
||||
function getDODOPool(address baseToken, address quoteToken)
|
||||
@@ -30,26 +30,30 @@ 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
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinDodoV2,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
/// @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.
|
||||
@@ -58,6 +62,7 @@ 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(
|
||||
@@ -68,31 +73,27 @@ contract DODOV2Sampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
(pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
|
||||
if (pool == address(0)) {
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
return (sellBase, pool, gasUsed, makerTokenAmounts);
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = _sampleSellForApproximateBuyFromDODOV2(
|
||||
abi.encode(takerToken, pool, sellBase), // taker token data
|
||||
abi.encode(makerToken, pool, sellBase), // maker token data
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
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, sellBase),
|
||||
getSwapQuoteCallback: this.sampleSwapFromDodoV2
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from DODO.
|
||||
@@ -103,6 +104,7 @@ 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(
|
||||
@@ -113,68 +115,30 @@ contract DODOV2Sampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
|
||||
returns (
|
||||
bool sellBase,
|
||||
address pool,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
(pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
|
||||
if (pool == address(0)) {
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
return (sellBase, pool, gasUsed, takerTokenAmounts);
|
||||
}
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, pool, !sellBase),
|
||||
takerTokenData: abi.encode(takerToken, pool, sellBase),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromDODOV2
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(pool, sellBase),
|
||||
buyTokenData: abi.encode(pool, !sellBase),
|
||||
getSwapQuoteCallback: this.sampleSwapFromDodoV2
|
||||
}),
|
||||
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,
|
||||
|
26
packages/asset-swapper/contracts/src/DelegateHackedERC20.sol
Normal file
26
packages/asset-swapper/contracts/src/DelegateHackedERC20.sol
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -24,44 +24,45 @@ import "./BalancerSampler.sol";
|
||||
import "./BalancerV2Sampler.sol";
|
||||
import "./BancorSampler.sol";
|
||||
import "./CurveSampler.sol";
|
||||
import "./CurveV2Sampler.sol";
|
||||
import "./DODOSampler.sol";
|
||||
import "./DODOV2Sampler.sol";
|
||||
import "./Eth2DaiSampler.sol";
|
||||
import "./KyberSampler.sol";
|
||||
import "./KyberDmmSampler.sol";
|
||||
import "./LidoSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
import "./MakerPSMSampler.sol";
|
||||
import "./MultiBridgeSampler.sol";
|
||||
import "./MStableSampler.sol";
|
||||
import "./MooniswapSampler.sol";
|
||||
import "./NativeOrderSampler.sol";
|
||||
import "./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,
|
||||
CurveSampler,
|
||||
CurveV2Sampler,
|
||||
DODOSampler,
|
||||
DODOV2Sampler,
|
||||
Eth2DaiSampler,
|
||||
KyberSampler,
|
||||
KyberDmmSampler,
|
||||
LidoSampler,
|
||||
LiquidityProviderSampler,
|
||||
MakerPSMSampler,
|
||||
MStableSampler,
|
||||
MooniswapSampler,
|
||||
MultiBridgeSampler,
|
||||
NativeOrderSampler,
|
||||
ShellSampler,
|
||||
SmoothySampler,
|
||||
TwoHopSampler,
|
||||
UniswapSampler,
|
||||
UniswapV2Sampler,
|
||||
@@ -74,11 +75,22 @@ 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 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -20,21 +20,38 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IEth2Dai.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinOasis.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
|
||||
contract Eth2DaiSampler is
|
||||
SamplerUtils
|
||||
MixinOasis,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Base gas limit for Eth2Dai calls.
|
||||
uint256 constant private ETH2DAI_CALL_GAS = 1000e3; // 1m
|
||||
|
||||
function sampleSwapFromOasis(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeOasis(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -44,29 +61,17 @@ contract Eth2DaiSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromOasis
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Eth2Dai/Oasis.
|
||||
@@ -74,6 +79,7 @@ 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(
|
||||
@@ -83,28 +89,17 @@ contract Eth2DaiSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(router),
|
||||
buyTokenData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromOasis
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
}
|
||||
|
30
packages/asset-swapper/contracts/src/GasOverhead.sol
Normal file
30
packages/asset-swapper/contracts/src/GasOverhead.sol
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
323
packages/asset-swapper/contracts/src/HackedERC20.sol
Normal file
323
packages/asset-swapper/contracts/src/HackedERC20.sol
Normal file
@@ -0,0 +1,323 @@
|
||||
// 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,6 +20,8 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinKyberDmm.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
interface IKyberDmmFactory {
|
||||
|
||||
function getPoolAtIndex(address token0, address token1, uint256 index)
|
||||
@@ -28,33 +30,36 @@ interface IKyberDmmFactory {
|
||||
returns (address);
|
||||
}
|
||||
|
||||
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
|
||||
contract KyberDmmSampler is
|
||||
MixinKyberDmm,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @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(
|
||||
@@ -63,32 +68,26 @@ contract KyberDmmSampler
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (address[] memory pools, uint256[] memory makerTokenAmounts)
|
||||
returns (
|
||||
address[] memory pools,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
{
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
pools = _getKyberDmmPools(router, path);
|
||||
if (pools.length == 0) {
|
||||
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;
|
||||
}
|
||||
return (pools, gasUsed, makerTokenAmounts);
|
||||
}
|
||||
|
||||
(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.
|
||||
@@ -96,6 +95,7 @@ contract KyberDmmSampler
|
||||
/// @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 +104,32 @@ contract KyberDmmSampler
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (address[] memory pools, uint256[] memory takerTokenAmounts)
|
||||
returns (
|
||||
address[] memory pools,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
{
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
pools = _getKyberDmmPools(router, path);
|
||||
if (pools.length == 0) {
|
||||
return (pools, takerTokenAmounts);
|
||||
return (pools, gasUsed, takerTokenAmounts);
|
||||
}
|
||||
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 reversedPath = new address[](path.length);
|
||||
for (uint256 i = 0; i < path.length; ++i) {
|
||||
reversedPath[i] = path[path.length - i - 1];
|
||||
}
|
||||
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(
|
||||
|
@@ -21,18 +21,22 @@ pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IKyberNetwork.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinKyber.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
contract KyberSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinKyber,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
/// @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;
|
||||
@@ -42,6 +46,26 @@ 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).
|
||||
@@ -49,6 +73,7 @@ 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,
|
||||
@@ -57,32 +82,29 @@ contract KyberSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bytes32 reserveId, bytes memory hint, uint256[] memory makerTokenAmounts)
|
||||
returns (
|
||||
bytes32 reserveId,
|
||||
bytes memory hint,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
reserveId = _getNextReserveId(opts, takerToken, makerToken);
|
||||
if (reserveId == 0x0) {
|
||||
return (reserveId, hint, makerTokenAmounts);
|
||||
return (reserveId, hint, gasUsed, makerTokenAmounts);
|
||||
}
|
||||
opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
|
||||
hint = opts.hint;
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 value = this.sampleSellFromKyberNetwork(
|
||||
opts,
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
makerTokenAmounts[i] = value;
|
||||
// Break early if there are 0 amounts
|
||||
if (makerTokenAmounts[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(opts.networkProxy, hint),
|
||||
getSwapQuoteCallback: this.sampleSwapFromKyber
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Kyber.
|
||||
@@ -92,6 +114,7 @@ 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,
|
||||
@@ -100,27 +123,30 @@ contract KyberSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bytes32 reserveId, bytes memory hint, uint256[] memory takerTokenAmounts)
|
||||
returns (
|
||||
bytes32 reserveId,
|
||||
bytes memory hint,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
reserveId = _getNextReserveId(opts, takerToken, makerToken);
|
||||
if (reserveId == 0x0) {
|
||||
return (reserveId, hint, takerTokenAmounts);
|
||||
return (reserveId, hint, gasUsed, takerTokenAmounts);
|
||||
}
|
||||
opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
|
||||
hint = opts.hint;
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, opts),
|
||||
takerTokenData: abi.encode(takerToken, opts),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromKyber
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(opts.networkProxy, hint),
|
||||
buyTokenData: abi.encode(opts.networkProxy, hint),
|
||||
getSwapQuoteCallback: this.sampleSwapFromKyber
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
return (reserveId, hint, takerTokenAmounts);
|
||||
}
|
||||
|
||||
function encodeKyberHint(
|
||||
@@ -201,73 +227,6 @@ 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,
|
||||
|
103
packages/asset-swapper/contracts/src/LidoSampler.sol
Normal file
103
packages/asset-swapper/contracts/src/LidoSampler.sol
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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/MixinLido.sol";
|
||||
import "./SwapRevertSampler.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
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Lido
|
||||
/// @param lido Address of the Lido 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 for each sample amount
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromLido(
|
||||
address lido,
|
||||
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(lido),
|
||||
getSwapQuoteCallback: this.sampleSwapFromLido
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Lido.
|
||||
/// @param lido Address of the Lido contract
|
||||
/// @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,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
// 1:1 rate so we can perform an WETH sell
|
||||
return this.sampleSellsFromLido(lido, takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -20,24 +20,38 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
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";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinZeroExBridge.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
|
||||
contract LiquidityProviderSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinZeroExBridge,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Default gas limit for liquidity provider calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
||||
|
||||
function sampleSwapFromLiquidityProvider(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeZeroExBridge(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -47,34 +61,18 @@ contract LiquidityProviderSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
bytes memory lpData;
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(providerAddress, lpData),
|
||||
getSwapQuoteCallback: this.sampleSwapFromLiquidityProvider
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
||||
@@ -82,6 +80,7 @@ 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(
|
||||
@@ -91,42 +90,18 @@ contract LiquidityProviderSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, providerAddress),
|
||||
takerTokenData: abi.encode(takerToken, providerAddress),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProvider
|
||||
bytes memory lpData;
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(providerAddress, lpData),
|
||||
buyTokenData: abi.encode(providerAddress, lpData),
|
||||
getSwapQuoteCallback: this.sampleSwapFromLiquidityProvider
|
||||
}),
|
||||
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,23 +20,38 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IMStable.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinMStable.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
|
||||
contract MStableSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinMStable,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Default gas limit for mStable calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 800e3; // 800k
|
||||
|
||||
function sampleSwapFromMStable(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeMStable(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -46,31 +61,17 @@ contract MStableSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMStable
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from MStable contract
|
||||
@@ -78,6 +79,7 @@ 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(
|
||||
@@ -87,41 +89,17 @@ contract MStableSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, router),
|
||||
takerTokenData: abi.encode(takerToken, router),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromMStable
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(router),
|
||||
buyTokenData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMStable
|
||||
}),
|
||||
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,69 +20,13 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
contract MakerPSMSampler is
|
||||
SamplerUtils
|
||||
MixinMakerPSM,
|
||||
SwapRevertSampler
|
||||
{
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
/// @dev Information about which PSM module to use
|
||||
struct MakerPsmInfo {
|
||||
@@ -91,18 +35,22 @@ contract MakerPSMSampler is
|
||||
address gemTokenAddress;
|
||||
}
|
||||
|
||||
/// @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
|
||||
function sampleSwapFromMakerPsm(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeMakerPsm(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Maker PSM
|
||||
function sampleSellsFromMakerPsm(
|
||||
@@ -112,29 +60,22 @@ contract MakerPSMSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(
|
||||
MakerPsmBridgeData({
|
||||
psmAddress: psmInfo.psmAddress,
|
||||
gemTokenAddres: psmInfo.gemTokenAddress
|
||||
})
|
||||
),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMakerPsm
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function sampleBuysFromMakerPsm(
|
||||
@@ -144,124 +85,21 @@ contract MakerPSMSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
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 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -20,17 +20,40 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IMooniswap.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinMooniswap.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
interface IMooniswapRegistry {
|
||||
function pools(address token1, address token2) external view returns(address);
|
||||
}
|
||||
|
||||
contract MooniswapSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinMooniswap,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Gas limit for Mooniswap calls.
|
||||
uint256 constant private MOONISWAP_CALL_GAS = 150e3; // 150k
|
||||
|
||||
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 Sample sell quotes from Mooniswap.
|
||||
/// @param registry Address of the Mooniswap Registry.
|
||||
@@ -38,6 +61,7 @@ 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(
|
||||
@@ -47,69 +71,22 @@ contract MooniswapSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (IMooniswap pool, uint256[] memory makerTokenAmounts)
|
||||
returns (address pool, uint256[] memory gasUsed, uint256[] memory 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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
pool = _getMooniswapPool(registry, takerToken, makerToken);
|
||||
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;
|
||||
return (pool, gasUsed, makerTokenAmounts);
|
||||
}
|
||||
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMooniswap
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Mooniswap.
|
||||
@@ -118,6 +95,7 @@ contract MooniswapSampler is
|
||||
/// @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(
|
||||
@@ -127,43 +105,42 @@ contract MooniswapSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (IMooniswap pool, uint256[] memory takerTokenAmounts)
|
||||
returns (address pool, uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
pool = _getMooniswapPool(registry, takerToken, makerToken);
|
||||
if (address(pool) == address(0)) {
|
||||
return (pool, gasUsed, takerTokenAmounts);
|
||||
}
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(registry, makerToken),
|
||||
takerTokenData: abi.encode(registry, takerToken),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromMooniswap
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(pool),
|
||||
buyTokenData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromMooniswap
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
|
||||
pool = IMooniswap(
|
||||
IMooniswapRegistry(registry).pools(takerToken, makerToken)
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromMooniswap(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
function _getMooniswapPool(
|
||||
address registry,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
internal
|
||||
returns (address pool)
|
||||
{
|
||||
(address registry, address mooniswapTakerToken) = abi.decode(takerTokenData, (address, address));
|
||||
(address _registry, address mooniswapMakerToken) = abi.decode(makerTokenData, (address, address));
|
||||
return sampleSingleSellFromMooniswapPool(
|
||||
registry,
|
||||
mooniswapTakerToken,
|
||||
mooniswapMakerToken,
|
||||
sellAmount
|
||||
);
|
||||
// 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 { }
|
||||
}
|
||||
}
|
||||
|
@@ -1,82 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./interfaces/IMultiBridge.sol";
|
||||
|
||||
|
||||
contract MultiBridgeSampler {
|
||||
|
||||
/// @dev Default gas limit for multibridge calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
||||
|
||||
/// @dev Sample sell quotes from MultiBridge.
|
||||
/// @param multibridge Address of the MultiBridge contract.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param intermediateToken The address of the intermediate token to
|
||||
/// use in an indirect route.
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromMultiBridge(
|
||||
address multibridge,
|
||||
address takerToken,
|
||||
address intermediateToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// If no address provided, return all zeros.
|
||||
if (multibridge == address(0)) {
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
multibridge.staticcall.gas(DEFAULT_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IMultiBridge(0).getSellQuote.selector,
|
||||
takerToken,
|
||||
intermediateToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
// Exit early if the amount is too high for the source to serve
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@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,28 +20,41 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./interfaces/IShell.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinShell.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
contract ShellSampler is
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
MixinShell,
|
||||
SwapRevertSampler
|
||||
{
|
||||
|
||||
struct ShellInfo {
|
||||
address poolAddress;
|
||||
}
|
||||
|
||||
/// @dev Default gas limit for Shell calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 300e3; // 300k
|
||||
function sampleSwapFromShell(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeShell(
|
||||
IERC20TokenV06(sellToken),
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -51,26 +64,17 @@ contract ShellSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromShell
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Shell pool contract
|
||||
@@ -78,6 +82,7 @@ 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(
|
||||
@@ -87,40 +92,17 @@ contract ShellSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, pool),
|
||||
takerTokenData: abi.encode(takerToken, pool),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromShell
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(pool),
|
||||
buyTokenData: abi.encode(pool),
|
||||
getSwapQuoteCallback: this.sampleSwapFromShell
|
||||
}),
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,156 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
// import "./interfaces/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];
|
||||
}
|
||||
}
|
412
packages/asset-swapper/contracts/src/SwapRevertSampler.sol
Normal file
412
packages/asset-swapper/contracts/src/SwapRevertSampler.sol
Normal file
@@ -0,0 +1,412 @@
|
||||
|
||||
|
||||
// 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,10 +40,11 @@ contract TwoHopSampler {
|
||||
returns (
|
||||
HopInfo memory firstHop,
|
||||
HopInfo memory secondHop,
|
||||
uint256 intermediateAssetAmount,
|
||||
uint256 buyAmount
|
||||
)
|
||||
{
|
||||
uint256 intermediateAssetAmount = 0;
|
||||
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]);
|
||||
@@ -57,7 +58,7 @@ contract TwoHopSampler {
|
||||
}
|
||||
}
|
||||
if (intermediateAssetAmount == 0) {
|
||||
return (firstHop, secondHop, buyAmount);
|
||||
return (firstHop, secondHop, intermediateAssetAmount, 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 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -20,32 +20,43 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswap.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
contract UniswapSampler is
|
||||
SamplerUtils
|
||||
MixinUniswap,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Gas limit for Uniswap calls.
|
||||
uint256 constant private UNISWAP_CALL_GAS = 150e3; // 150k
|
||||
|
||||
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 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(
|
||||
@@ -55,59 +66,24 @@ contract UniswapSampler is
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
bridgeData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswap
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -117,98 +93,18 @@ contract UniswapSampler is
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_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))
|
||||
(gasUsed, takerTokenAmounts) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: takerToken,
|
||||
buyToken: makerToken,
|
||||
sellTokenData: abi.encode(router),
|
||||
buyTokenData: abi.encode(router),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswap
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
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.
|
||||
@@ -21,17 +21,36 @@ 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
|
||||
contract UniswapV2Sampler is
|
||||
MixinUniswapV2,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Gas limit for UniswapV2 calls.
|
||||
uint256 constant private UNISWAPV2_CALL_GAS = 150e3; // 150k
|
||||
|
||||
function sampleSwapFromUniswapV2(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeUniswapV2(
|
||||
IERC20TokenV06(buyToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -40,34 +59,24 @@ contract UniswapV2Sampler
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
(gasUsed, makerTokenAmounts) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: path[0],
|
||||
buyToken: path[path.length - 1],
|
||||
bridgeData: abi.encode(router, path),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswapV2
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -76,27 +85,22 @@ contract UniswapV2Sampler
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
returns (uint256[] memory gasUsed, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
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;
|
||||
}
|
||||
address[] memory reversedPath = new address[](path.length);
|
||||
for (uint256 i = 0; i < path.length; ++i) {
|
||||
reversedPath[i] = path[path.length - i - 1];
|
||||
}
|
||||
|
||||
(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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -21,18 +21,16 @@ pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
|
||||
import "@0x/contracts-zero-ex/contracts/src/transformers/bridges/mixins/MixinUniswapV3.sol";
|
||||
import "./SwapRevertSampler.sol";
|
||||
|
||||
interface IUniswapV3Quoter {
|
||||
function factory()
|
||||
external
|
||||
view
|
||||
returns (IUniswapV3Factory factory);
|
||||
function quoteExactInput(bytes memory path, uint256 amountIn)
|
||||
external
|
||||
returns (uint256 amountOut);
|
||||
function quoteExactOutput(bytes memory path, uint256 amountOut)
|
||||
external
|
||||
returns (uint256 amountIn);
|
||||
}
|
||||
|
||||
interface IUniswapV3Factory {
|
||||
@@ -48,26 +46,47 @@ interface IUniswapV3Pool {
|
||||
function fee() external view returns (uint24);
|
||||
}
|
||||
|
||||
contract UniswapV3Sampler
|
||||
contract UniswapV3Sampler is
|
||||
MixinUniswapV3,
|
||||
SwapRevertSampler
|
||||
{
|
||||
/// @dev Gas limit for UniswapV3 calls. This is 100% a guess.
|
||||
uint256 constant private QUOTE_GAS = 300e3;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
function sampleSwapFromUniswapV3(
|
||||
address sellToken,
|
||||
address buyToken,
|
||||
bytes memory bridgeData,
|
||||
uint256 takerTokenAmount
|
||||
)
|
||||
external
|
||||
returns (uint256)
|
||||
{
|
||||
return _tradeUniswapV3(
|
||||
IERC20TokenV06(sellToken),
|
||||
takerTokenAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from UniswapV3.
|
||||
/// @param quoter UniswapV3 Quoter contract.
|
||||
/// @param router UniswapV3 Router contract.
|
||||
/// @param path Token route. Should be takerToken -> makerToken
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return uniswapPaths The encoded uniswap path for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromUniswapV3(
|
||||
IUniswapV3Quoter quoter,
|
||||
address router,
|
||||
IERC20TokenV06[] memory path,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bytes[] memory uniswapPaths,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
{
|
||||
@@ -75,50 +94,57 @@ contract UniswapV3Sampler
|
||||
_getValidPoolPaths(quoter.factory(), path, 0);
|
||||
|
||||
makerTokenAmounts = new uint256[](takerTokenAmounts.length);
|
||||
gasUsed = new uint256[](takerTokenAmounts.length);
|
||||
uniswapPaths = new bytes[](takerTokenAmounts.length);
|
||||
|
||||
for (uint256 i = 0; i < takerTokenAmounts.length; ++i) {
|
||||
// Pick the best result from all the paths.
|
||||
bytes memory topUniswapPath;
|
||||
uint256 topBuyAmount = 0;
|
||||
for (uint256 j = 0; j < poolPaths.length; ++j) {
|
||||
bytes memory uniswapPath = _toUniswapPath(path, poolPaths[j]);
|
||||
try
|
||||
quoter.quoteExactInput
|
||||
{ gas: QUOTE_GAS }
|
||||
(uniswapPath, takerTokenAmounts[i])
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
if (topBuyAmount <= buyAmount) {
|
||||
topBuyAmount = buyAmount;
|
||||
topUniswapPath = uniswapPath;
|
||||
}
|
||||
} catch { }
|
||||
for (uint256 i = 0; i < poolPaths.length; ++i) {
|
||||
bytes memory _uniswapPath = _toUniswapPath(path, poolPaths[i]);
|
||||
(
|
||||
uint256[] memory _gasUsed,
|
||||
uint256[] memory _makerTokenAmounts
|
||||
) = _sampleSwapQuotesRevert(
|
||||
SwapRevertSamplerQuoteOpts({
|
||||
sellToken: address(path[0]),
|
||||
buyToken: address(path[path.length - 1]),
|
||||
bridgeData: abi.encode(router, _uniswapPath),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswapV3
|
||||
}),
|
||||
takerTokenAmounts
|
||||
);
|
||||
for (uint256 j = 0; j < _makerTokenAmounts.length; ++j) {
|
||||
// Break early if we can't complete the sells.
|
||||
if (_makerTokenAmounts[j] == 0) {
|
||||
break;
|
||||
}
|
||||
// If this is better than what we have found, prefer it
|
||||
if (makerTokenAmounts[j] <= _makerTokenAmounts[j]) {
|
||||
makerTokenAmounts[j] = _makerTokenAmounts[j];
|
||||
gasUsed[j] = _gasUsed[j];
|
||||
uniswapPaths[j] = _uniswapPath;
|
||||
}
|
||||
}
|
||||
// Break early if we can't complete the buys.
|
||||
if (topBuyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = topBuyAmount;
|
||||
uniswapPaths[i] = topUniswapPath;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from UniswapV3.
|
||||
/// @param quoter UniswapV3 Quoter contract.
|
||||
/// @param router UniswapV3 Router contract.
|
||||
/// @param path Token route. Should be takerToken -> makerToken.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return uniswapPaths The encoded uniswap path for each sample.
|
||||
/// @return gasUsed gas consumed in each sample sell
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromUniswapV3(
|
||||
IUniswapV3Quoter quoter,
|
||||
address router,
|
||||
IERC20TokenV06[] memory path,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
returns (
|
||||
bytes[] memory uniswapPaths,
|
||||
uint256[] memory gasUsed,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
{
|
||||
@@ -127,37 +153,43 @@ contract UniswapV3Sampler
|
||||
IERC20TokenV06[] memory reversedPath = _reverseTokenPath(path);
|
||||
|
||||
takerTokenAmounts = new uint256[](makerTokenAmounts.length);
|
||||
gasUsed = new uint256[](makerTokenAmounts.length);
|
||||
uniswapPaths = new bytes[](makerTokenAmounts.length);
|
||||
|
||||
for (uint256 i = 0; i < makerTokenAmounts.length; ++i) {
|
||||
// Pick the best result from all the paths.
|
||||
bytes memory topUniswapPath;
|
||||
uint256 topSellAmount = 0;
|
||||
for (uint256 j = 0; j < poolPaths.length; ++j) {
|
||||
// quoter requires path to be reversed for buys.
|
||||
bytes memory uniswapPath = _toUniswapPath(
|
||||
reversedPath,
|
||||
_reversePoolPath(poolPaths[j])
|
||||
);
|
||||
try
|
||||
quoter.quoteExactOutput
|
||||
{ gas: QUOTE_GAS }
|
||||
(uniswapPath, makerTokenAmounts[i])
|
||||
returns (uint256 sellAmount)
|
||||
{
|
||||
if (topSellAmount == 0 || topSellAmount >= sellAmount) {
|
||||
topSellAmount = sellAmount;
|
||||
// But the output path should still be encoded for sells.
|
||||
topUniswapPath = _toUniswapPath(path, poolPaths[j]);
|
||||
}
|
||||
} catch {}
|
||||
for (uint256 i = 0; i < poolPaths.length; ++i) {
|
||||
(
|
||||
uint256[] memory _gasUsed,
|
||||
uint256[] memory _takerTokenAmounts
|
||||
) = _sampleSwapApproximateBuys(
|
||||
SwapRevertSamplerBuyQuoteOpts({
|
||||
sellToken: address(path[0]),
|
||||
buyToken: address(path[path.length - 1]),
|
||||
sellTokenData: abi.encode(router, _toUniswapPath(path, poolPaths[i])),
|
||||
buyTokenData: abi.encode(
|
||||
router,
|
||||
_toUniswapPath(
|
||||
reversedPath,
|
||||
_reversePoolPath(poolPaths[i])
|
||||
)
|
||||
),
|
||||
getSwapQuoteCallback: this.sampleSwapFromUniswapV3
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
|
||||
for (uint256 j = 0; j < _takerTokenAmounts.length; ++j) {
|
||||
// Break early if we can't complete the buys.
|
||||
if (_takerTokenAmounts[j] == 0) {
|
||||
break;
|
||||
}
|
||||
// We can go from high to low here
|
||||
if (takerTokenAmounts[j] == 0 || takerTokenAmounts[j] >= _takerTokenAmounts[j]) {
|
||||
takerTokenAmounts[j] = _takerTokenAmounts[j];
|
||||
gasUsed[j] = _gasUsed[j];
|
||||
// But the output path should still be encoded for sells.
|
||||
uniswapPaths[j] = _toUniswapPath(path, poolPaths[i]);
|
||||
}
|
||||
}
|
||||
// Break early if we can't complete the buys.
|
||||
if (topSellAmount == 0) {
|
||||
break;
|
||||
}
|
||||
takerTokenAmounts[i] = topSellAmount;
|
||||
uniswapPaths[i] = topUniswapPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +300,7 @@ contract UniswapV3Sampler
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Must have a balance of both tokens.
|
||||
// // Must have a balance of both tokens.
|
||||
if (pool.token0().balanceOf(address(pool)) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -77,4 +77,24 @@ contract UtilitySampler {
|
||||
assembly { size := extcodesize(account) }
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
function getCode(address addr)
|
||||
public
|
||||
view
|
||||
returns (bytes memory code)
|
||||
{
|
||||
assembly {
|
||||
// retrieve the size of the code, this needs assembly
|
||||
let size := extcodesize(addr)
|
||||
// allocate output byte array - this could also be done without assembly
|
||||
// by using o_code = new bytes(size)
|
||||
code := mload(0x40)
|
||||
// new "memory end" including padding
|
||||
mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
|
||||
// store length in memory
|
||||
mstore(code, size)
|
||||
// actually retrieve the code, this needs assembly
|
||||
extcodecopy(addr, add(code, 0x20), 0, size)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,44 +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;
|
||||
|
||||
|
||||
interface IBalancer {
|
||||
function isBound(address t) external view returns (bool);
|
||||
function getDenormalizedWeight(address token) external view returns (uint256);
|
||||
function getBalance(address token) external view returns (uint256);
|
||||
function getSwapFee() external view returns (uint256);
|
||||
function calcOutGivenIn(
|
||||
uint256 tokenBalanceIn,
|
||||
uint256 tokenWeightIn,
|
||||
uint256 tokenBalanceOut,
|
||||
uint256 tokenWeightOut,
|
||||
uint256 tokenAmountIn,
|
||||
uint256 swapFee
|
||||
) external pure returns (uint256 tokenAmountOut);
|
||||
function calcInGivenOut(
|
||||
uint256 tokenBalanceIn,
|
||||
uint256 tokenWeightIn,
|
||||
uint256 tokenBalanceOut,
|
||||
uint256 tokenWeightOut,
|
||||
uint256 tokenAmountOut,
|
||||
uint256 swapFee
|
||||
) external pure returns (uint256 tokenAmountIn);
|
||||
}
|
@@ -1,33 +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;
|
||||
|
||||
|
||||
interface IBancor {}
|
||||
|
||||
interface IBancorNetwork {
|
||||
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);
|
||||
}
|
@@ -1,72 +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;
|
||||
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
interface ICurve {
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// This function exists on later versions of Curve (USDC/DAI/USDT)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
/// @param minBuyAmount The minimum buy amount of the token being bought.
|
||||
function exchange_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken`
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
function get_dy_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dy);
|
||||
|
||||
/// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
|
||||
/// This function exists on later versions of Curve (USDC/DAI/USDT)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param buyAmount The amount of token being bought.
|
||||
function get_dx_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 buyAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dx);
|
||||
|
||||
/// @dev Get the underlying token address from the token index
|
||||
/// @param i The token index.
|
||||
function underlying_coins(
|
||||
int128 i
|
||||
)
|
||||
external
|
||||
returns (address tokenAddress);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user