Compare commits
19 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
018e25345b | ||
|
b60fa8a7d7 | ||
|
048d8dee60 | ||
|
927fe2b58b | ||
|
89948b360c | ||
|
561b60a24d | ||
|
4f82543bdf | ||
|
3133c509f9 | ||
|
426c15692d | ||
|
8c87a77faa | ||
|
d2018f07a2 | ||
|
d2e57d8163 | ||
|
7403c0255a | ||
|
75dcd687e2 | ||
|
afd4805421 | ||
|
6aa582d140 | ||
|
534d92fa00 | ||
|
37aae134ab | ||
|
36bd8f68c9 |
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "3.6.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "3.6.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "3.6.4",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.6.6 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.5 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.4 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.6.4",
|
||||
"version": "3.6.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,10 +52,10 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contract-wrappers": "^13.9.5",
|
||||
"@0x/contract-wrappers": "^13.10.1",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -80,11 +80,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contracts-erc1155": "^2.1.13",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-erc721": "^3.1.13",
|
||||
"@0x/contracts-exchange-libs": "^4.3.13",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/contracts-erc1155": "^2.1.15",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-erc721": "^3.1.15",
|
||||
"@0x/contracts-exchange-libs": "^4.3.15",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/types": "^3.3.0",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^6.1.0",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "1.1.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "1.1.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "1.1.12",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.14 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.13 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.12 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-broker",
|
||||
"version": "1.1.12",
|
||||
"version": "1.1.14",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,14 +52,14 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-erc721": "^3.1.13",
|
||||
"@0x/contracts-exchange": "^3.2.13",
|
||||
"@0x/contracts-exchange-libs": "^4.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-erc721": "^3.1.15",
|
||||
"@0x/contracts-exchange": "^3.2.15",
|
||||
"@0x/contracts-exchange-libs": "^4.3.15",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -85,7 +85,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^6.1.0",
|
||||
"ethereum-types": "^3.3.3"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "3.1.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "3.1.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "3.1.13",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.15 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.14 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.13 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.1.13",
|
||||
"version": "3.1.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,12 +53,12 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-dev-utils": "^1.3.11",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.13",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -84,10 +84,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.17",
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contract-addresses": "^5.2.0",
|
||||
"@0x/contracts-exchange": "^3.2.13",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contract-addresses": "^5.4.0",
|
||||
"@0x/contracts-exchange": "^3.2.15",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/json-schemas": "^5.3.3",
|
||||
"@0x/types": "^3.3.0",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "1.3.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "1.3.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "1.3.11",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.3.13 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.12 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.11 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.3.11",
|
||||
"version": "1.3.13",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -43,10 +43,10 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/assert": "^3.0.17",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "2.1.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "2.1.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "2.1.13",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.1.15 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.14 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.13 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.1.13",
|
||||
"version": "2.1.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,7 +54,7 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -81,7 +81,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/utils": "^6.1.0",
|
||||
"@0x/web3-wrapper": "^7.2.8",
|
||||
"lodash": "^4.17.11"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "3.2.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "3.2.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "3.2.7",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.9 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.8 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.7 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.2.7",
|
||||
"version": "3.2.9",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,8 +53,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "3.1.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "3.1.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "3.1.13",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.15 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.14 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.13 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.1.13",
|
||||
"version": "3.1.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,8 +54,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "4.2.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "4.2.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "4.2.13",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.15 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.14 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.13 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.2.13",
|
||||
"version": "4.2.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,18 +53,18 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-dev-utils": "^1.3.11",
|
||||
"@0x/contracts-erc1155": "^2.1.13",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-erc721": "^3.1.13",
|
||||
"@0x/contracts-exchange": "^3.2.13",
|
||||
"@0x/contracts-exchange-libs": "^4.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.13",
|
||||
"@0x/contracts-erc1155": "^2.1.15",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-erc721": "^3.1.15",
|
||||
"@0x/contracts-exchange": "^3.2.15",
|
||||
"@0x/contracts-exchange-libs": "^4.3.15",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "4.3.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "4.3.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "4.3.13",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.3.15 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.14 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.13 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.3.13",
|
||||
"version": "4.3.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -81,9 +81,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/types": "^3.3.0",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^6.1.0",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "3.2.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "3.2.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "3.2.13",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.15 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.14 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.13 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.2.13",
|
||||
"version": "3.2.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,13 +53,13 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-exchange-libs": "^4.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-exchange-libs": "^4.3.15",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-multisig": "^4.1.13",
|
||||
"@0x/contracts-staking": "^2.0.20",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-multisig": "^4.1.15",
|
||||
"@0x/contracts-staking": "^2.0.22",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -89,11 +89,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contracts-dev-utils": "^1.3.11",
|
||||
"@0x/contracts-erc1155": "^2.1.13",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-erc721": "^3.1.13",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/contracts-dev-utils": "^1.3.13",
|
||||
"@0x/contracts-erc1155": "^2.1.15",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-erc721": "^3.1.15",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/utils": "^6.1.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "6.2.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "6.2.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "6.2.7",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.2.9 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.2.8 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.2.7 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "6.2.7",
|
||||
"version": "6.2.9",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,16 +53,16 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-dev-utils": "^1.3.11",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-erc721": "^3.1.13",
|
||||
"@0x/contracts-exchange": "^3.2.13",
|
||||
"@0x/contracts-exchange-libs": "^4.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.13",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-erc721": "^3.1.15",
|
||||
"@0x/contracts-exchange": "^3.2.15",
|
||||
"@0x/contracts-exchange-libs": "^4.3.15",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -91,7 +91,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"ethereum-types": "^3.3.3"
|
||||
},
|
||||
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "2.7.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605320370,
|
||||
"version": "2.7.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "2.7.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604620645,
|
||||
"version": "2.7.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "2.7.6",
|
||||
|
@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.7.10 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.7.9 - _November 14, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.7.8 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.7.7 - _November 5, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.7.6 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-integrations",
|
||||
"version": "2.7.6",
|
||||
"version": "2.7.10",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,20 +52,20 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contract-addresses": "^5.2.0",
|
||||
"@0x/contract-wrappers": "^13.9.5",
|
||||
"@0x/contracts-broker": "^1.1.12",
|
||||
"@0x/contracts-coordinator": "^3.1.13",
|
||||
"@0x/contracts-dev-utils": "^1.3.11",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.13",
|
||||
"@0x/contracts-exchange-libs": "^4.3.13",
|
||||
"@0x/contracts-extensions": "^6.2.7",
|
||||
"@0x/contract-addresses": "^5.4.0",
|
||||
"@0x/contract-wrappers": "^13.10.1",
|
||||
"@0x/contracts-broker": "^1.1.14",
|
||||
"@0x/contracts-coordinator": "^3.1.15",
|
||||
"@0x/contracts-dev-utils": "^1.3.13",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.15",
|
||||
"@0x/contracts-exchange-libs": "^4.3.15",
|
||||
"@0x/contracts-extensions": "^6.2.9",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/coordinator-server": "^1.0.5",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/migrations": "^6.4.7",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/migrations": "^6.5.1",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/web3-wrapper": "^7.2.8",
|
||||
@@ -91,17 +91,17 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/asset-swapper": "^5.0.2",
|
||||
"@0x/asset-swapper": "^5.2.0",
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-erc1155": "^2.1.13",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-erc721": "^3.1.13",
|
||||
"@0x/contracts-exchange": "^3.2.13",
|
||||
"@0x/contracts-multisig": "^4.1.13",
|
||||
"@0x/contracts-staking": "^2.0.20",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-zero-ex": "^0.8.0",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-erc1155": "^2.1.15",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-erc721": "^3.1.15",
|
||||
"@0x/contracts-exchange": "^3.2.15",
|
||||
"@0x/contracts-multisig": "^4.1.15",
|
||||
"@0x/contracts-staking": "^2.0.22",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-zero-ex": "^0.10.0",
|
||||
"@0x/subproviders": "^6.1.9",
|
||||
"@0x/types": "^3.3.0",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "4.1.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "4.1.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "4.1.13",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.15 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.14 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.13 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-multisig",
|
||||
"version": "4.1.13",
|
||||
"version": "4.1.15",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,11 +50,11 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "2.0.22",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "2.0.21",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "2.0.20",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.22 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.21 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.20 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-staking",
|
||||
"version": "2.0.20",
|
||||
"version": "2.0.22",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,14 +54,14 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-asset-proxy": "^3.6.4",
|
||||
"@0x/contracts-dev-utils": "^1.3.11",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-exchange-libs": "^4.3.13",
|
||||
"@0x/contracts-asset-proxy": "^3.6.6",
|
||||
"@0x/contracts-dev-utils": "^1.3.13",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-exchange-libs": "^4.3.15",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-utils": "^4.6.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^6.1.0",
|
||||
"ethereum-types": "^3.3.3",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "5.3.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "5.3.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "5.3.10",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.3.12 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.3.11 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.3.10 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.3.10",
|
||||
"version": "5.3.12",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,10 +44,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.17",
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/contract-addresses": "^5.2.0",
|
||||
"@0x/contract-addresses": "^5.4.0",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/json-schemas": "^5.3.3",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/sol-coverage": "^4.0.18",
|
||||
"@0x/sol-profiler": "^4.1.8",
|
||||
"@0x/sol-trace": "^3.0.18",
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"version": "4.6.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `uint128` functions to `LibSafeMathV06`",
|
||||
"pr": 27
|
||||
}
|
||||
],
|
||||
"timestamp": 1605763885
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "4.5.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "4.5.7",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.6.0 - _November 19, 2020_
|
||||
|
||||
* Add `uint128` functions to `LibSafeMathV06` (#27)
|
||||
|
||||
## v4.5.8 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.5.7 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -105,4 +105,86 @@ library LibSafeMathV06 {
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
function safeMul128(uint128 a, uint128 b)
|
||||
internal
|
||||
pure
|
||||
returns (uint128)
|
||||
{
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint128 c = a * b;
|
||||
if (c / a != b) {
|
||||
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
|
||||
LibSafeMathRichErrorsV06.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
function safeDiv128(uint128 a, uint128 b)
|
||||
internal
|
||||
pure
|
||||
returns (uint128)
|
||||
{
|
||||
if (b == 0) {
|
||||
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
|
||||
LibSafeMathRichErrorsV06.BinOpErrorCodes.DIVISION_BY_ZERO,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
uint128 c = a / b;
|
||||
return c;
|
||||
}
|
||||
|
||||
function safeSub128(uint128 a, uint128 b)
|
||||
internal
|
||||
pure
|
||||
returns (uint128)
|
||||
{
|
||||
if (b > a) {
|
||||
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
|
||||
LibSafeMathRichErrorsV06.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
return a - b;
|
||||
}
|
||||
|
||||
function safeAdd128(uint128 a, uint128 b)
|
||||
internal
|
||||
pure
|
||||
returns (uint128)
|
||||
{
|
||||
uint128 c = a + b;
|
||||
if (c < a) {
|
||||
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
|
||||
LibSafeMathRichErrorsV06.BinOpErrorCodes.ADDITION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
function max128(uint128 a, uint128 b)
|
||||
internal
|
||||
pure
|
||||
returns (uint128)
|
||||
{
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
function min128(uint128 a, uint128 b)
|
||||
internal
|
||||
pure
|
||||
returns (uint128)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.5.7",
|
||||
"version": "4.6.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,9 +52,9 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.3.0",
|
||||
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"version": "0.10.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `checkAllowance` flag to LibTokenSpender.spendERC20Tokens",
|
||||
"pr": 39
|
||||
},
|
||||
{
|
||||
"note": "Use new `checkAllowance` flag in LiquidityProviderFeature, TransformERC20Feature, and MetaTransactionsFeature",
|
||||
"pr": 39
|
||||
}
|
||||
],
|
||||
"timestamp": 1605763885
|
||||
},
|
||||
{
|
||||
"version": "0.9.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Rewrite the ZeroEx contract in Yul",
|
||||
"pr": 23
|
||||
},
|
||||
{
|
||||
"note": "Update LiquidityProviderFeature to use off-chain registry and sandbox",
|
||||
"pr": 16
|
||||
},
|
||||
{
|
||||
"note": "Update ILiquidityProvider interface",
|
||||
"pr": 16
|
||||
},
|
||||
{
|
||||
"note": "Update ProtocolFeeUnfunded event to emit order hash",
|
||||
"pr": 16
|
||||
}
|
||||
],
|
||||
"timestamp": 1605302002
|
||||
},
|
||||
{
|
||||
"version": "0.8.0",
|
||||
"changes": [
|
||||
@@ -33,6 +69,10 @@
|
||||
{
|
||||
"note": "Add `LibSignature` library",
|
||||
"pr": 21
|
||||
},
|
||||
{
|
||||
"note": "Add `LimitOrdersFeature`",
|
||||
"pr": 27
|
||||
}
|
||||
],
|
||||
"timestamp": 1604355662
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.10.0 - _November 19, 2020_
|
||||
|
||||
* Add `checkAllowance` flag to LibTokenSpender.spendERC20Tokens (#39)
|
||||
* Use new `checkAllowance` flag in LiquidityProviderFeature, TransformERC20Feature, and MetaTransactionsFeature (#39)
|
||||
|
||||
## v0.9.0 - _November 13, 2020_
|
||||
|
||||
* Rewrite the ZeroEx contract in Yul (#23)
|
||||
* Update LiquidityProviderFeature to use off-chain registry and sandbox (#16)
|
||||
* Update ILiquidityProvider interface (#16)
|
||||
* Update ProtocolFeeUnfunded event to emit order hash (#16)
|
||||
|
||||
## v0.8.0 - _November 3, 2020_
|
||||
|
||||
* Trust LP boughtAmount return value (#29)
|
||||
@@ -18,6 +30,7 @@ CHANGELOG
|
||||
|
||||
* Add support for collecting protocol fees in ETH or WETH (#2)
|
||||
* Add `LibSignature` library (#21)
|
||||
* Add `LimitOrdersFeature` (#27)
|
||||
|
||||
## v0.5.1 - _October 28, 2020_
|
||||
|
||||
|
@@ -19,7 +19,8 @@
|
||||
"evm.bytecode.object",
|
||||
"evm.bytecode.sourceMap",
|
||||
"evm.deployedBytecode.object",
|
||||
"evm.deployedBytecode.sourceMap"
|
||||
"evm.deployedBytecode.sourceMap",
|
||||
"evm.methodIdentifiers"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import "./features/ITransformERC20Feature.sol";
|
||||
import "./features/IMetaTransactionsFeature.sol";
|
||||
import "./features/IUniswapFeature.sol";
|
||||
import "./features/ILiquidityProviderFeature.sol";
|
||||
import "./features/INativeOrdersFeature.sol";
|
||||
|
||||
|
||||
/// @dev Interface for a fully featured Exchange Proxy.
|
||||
@@ -38,20 +39,11 @@ interface IZeroEx is
|
||||
ITransformERC20Feature,
|
||||
IMetaTransactionsFeature,
|
||||
IUniswapFeature,
|
||||
ILiquidityProviderFeature
|
||||
ILiquidityProviderFeature,
|
||||
INativeOrdersFeature
|
||||
{
|
||||
// solhint-disable state-visibility
|
||||
|
||||
/// @dev Fallback for just receiving ether.
|
||||
receive() external payable;
|
||||
|
||||
// solhint-enable state-visibility
|
||||
|
||||
/// @dev Get the implementation contract of a registered function.
|
||||
/// @param selector The function selector.
|
||||
/// @return impl The implementation contract address.
|
||||
function getFunctionImplementation(bytes4 selector)
|
||||
external
|
||||
view
|
||||
returns (address impl);
|
||||
}
|
||||
|
@@ -19,19 +19,12 @@
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
|
||||
import "./migrations/LibBootstrap.sol";
|
||||
import "./features/BootstrapFeature.sol";
|
||||
import "./storage/LibProxyStorage.sol";
|
||||
import "./errors/LibProxyRichErrors.sol";
|
||||
|
||||
|
||||
/// @dev An extensible proxy contract that serves as a universal entry point for
|
||||
/// interacting with the 0x protocol.
|
||||
contract ZeroEx {
|
||||
// solhint-disable separate-by-one-line-in-contract,indent,var-name-mixedcase
|
||||
using LibBytesV06 for bytes;
|
||||
|
||||
/// @dev Construct this contract and register the `BootstrapFeature` feature.
|
||||
/// After constructing this contract, `bootstrap()` should be called
|
||||
/// by `bootstrap()` to seed the initial feature set.
|
||||
@@ -44,48 +37,55 @@ contract ZeroEx {
|
||||
address(bootstrap);
|
||||
}
|
||||
|
||||
|
||||
// solhint-disable state-visibility
|
||||
|
||||
/// @dev Forwards calls to the appropriate implementation contract.
|
||||
fallback() external payable {
|
||||
bytes4 selector = msg.data.readBytes4(0);
|
||||
address impl = getFunctionImplementation(selector);
|
||||
if (impl == address(0)) {
|
||||
_revertWithData(LibProxyRichErrors.NotImplementedError(selector));
|
||||
// This is used in assembly below as impls_slot.
|
||||
mapping(bytes4 => address) storage impls =
|
||||
LibProxyStorage.getStorage().impls;
|
||||
|
||||
assembly {
|
||||
let cdlen := calldatasize()
|
||||
|
||||
// equivalent of receive() external payable {}
|
||||
if iszero(cdlen) {
|
||||
return(0, 0)
|
||||
}
|
||||
|
||||
// Store at 0x40, to leave 0x00-0x3F for slot calculation below.
|
||||
calldatacopy(0x40, 0, cdlen)
|
||||
let selector := and(mload(0x40), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
|
||||
|
||||
// Slot for impls[selector] is keccak256(selector . impls_slot).
|
||||
mstore(0, selector)
|
||||
mstore(0x20, impls_slot)
|
||||
let slot := keccak256(0, 0x40)
|
||||
|
||||
let delegate := sload(slot)
|
||||
if iszero(delegate) {
|
||||
// Revert with:
|
||||
// abi.encodeWithSelector(
|
||||
// bytes4(keccak256("NotImplementedError(bytes4)")),
|
||||
// selector)
|
||||
mstore(0, 0x734e6e1c00000000000000000000000000000000000000000000000000000000)
|
||||
mstore(4, selector)
|
||||
revert(0, 0x24)
|
||||
}
|
||||
|
||||
let success := delegatecall(
|
||||
gas(),
|
||||
delegate,
|
||||
0x40, cdlen,
|
||||
0, 0
|
||||
)
|
||||
let rdlen := returndatasize()
|
||||
returndatacopy(0, 0, rdlen)
|
||||
if success {
|
||||
return(0, rdlen)
|
||||
}
|
||||
revert(0, rdlen)
|
||||
}
|
||||
|
||||
(bool success, bytes memory resultData) = impl.delegatecall(msg.data);
|
||||
if (!success) {
|
||||
_revertWithData(resultData);
|
||||
}
|
||||
_returnWithData(resultData);
|
||||
}
|
||||
|
||||
/// @dev Fallback for just receiving ether.
|
||||
receive() external payable {}
|
||||
|
||||
// solhint-enable state-visibility
|
||||
|
||||
/// @dev Get the implementation contract of a registered function.
|
||||
/// @param selector The function selector.
|
||||
/// @return impl The implementation contract address.
|
||||
function getFunctionImplementation(bytes4 selector)
|
||||
public
|
||||
view
|
||||
returns (address impl)
|
||||
{
|
||||
return LibProxyStorage.getStorage().impls[selector];
|
||||
}
|
||||
|
||||
/// @dev Revert with arbitrary bytes.
|
||||
/// @param data Revert data.
|
||||
function _revertWithData(bytes memory data) private pure {
|
||||
assembly { revert(add(data, 32), mload(data)) }
|
||||
}
|
||||
|
||||
/// @dev Return with arbitrary bytes.
|
||||
/// @param data Return data.
|
||||
function _returnWithData(bytes memory data) private pure {
|
||||
assembly { return(add(data, 32), mload(data)) }
|
||||
}
|
||||
}
|
||||
|
@@ -45,19 +45,4 @@ library LibLiquidityProviderRichErrors {
|
||||
minBuyAmount
|
||||
);
|
||||
}
|
||||
|
||||
function NoLiquidityProviderForMarketError(
|
||||
address xAsset,
|
||||
address yAsset
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("NoLiquidityProviderForMarketError(address,address)")),
|
||||
xAsset,
|
||||
yAsset
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
|
||||
library LibNativeOrdersRichErrors {
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
|
||||
function ProtocolFeeRefundFailed(
|
||||
address receiver,
|
||||
uint256 refundAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("ProtocolFeeRefundFailed(address,uint256)")),
|
||||
receiver,
|
||||
refundAmount
|
||||
);
|
||||
}
|
||||
|
||||
function OrderNotFillableByOriginError(
|
||||
bytes32 orderHash,
|
||||
address txOrigin,
|
||||
address orderTxOrigin
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("OrderNotFillableByOriginError(bytes32,address,address)")),
|
||||
orderHash,
|
||||
txOrigin,
|
||||
orderTxOrigin
|
||||
);
|
||||
}
|
||||
|
||||
function OrderNotFillableError(
|
||||
bytes32 orderHash,
|
||||
uint8 orderStatus
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("OrderNotFillableError(bytes32,uint8)")),
|
||||
orderHash,
|
||||
orderStatus
|
||||
);
|
||||
}
|
||||
|
||||
function OrderNotSignedByMakerError(
|
||||
bytes32 orderHash,
|
||||
address signer,
|
||||
address maker
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("OrderNotSignedByMakerError(bytes32,address,address)")),
|
||||
orderHash,
|
||||
signer,
|
||||
maker
|
||||
);
|
||||
}
|
||||
|
||||
function OrderNotFillableBySenderError(
|
||||
bytes32 orderHash,
|
||||
address sender,
|
||||
address orderSender
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("OrderNotFillableBySenderError(bytes32,address,address)")),
|
||||
orderHash,
|
||||
sender,
|
||||
orderSender
|
||||
);
|
||||
}
|
||||
|
||||
function OrderNotFillableByTakerError(
|
||||
bytes32 orderHash,
|
||||
address taker,
|
||||
address orderTaker
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("OrderNotFillableByTakerError(bytes32,address,address)")),
|
||||
orderHash,
|
||||
taker,
|
||||
orderTaker
|
||||
);
|
||||
}
|
||||
|
||||
function CancelSaltTooLowError(
|
||||
uint256 minValidSalt,
|
||||
uint256 oldMinValidSalt
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("CancelSaltTooLowError(uint256,uint256)")),
|
||||
minValidSalt,
|
||||
oldMinValidSalt
|
||||
);
|
||||
}
|
||||
|
||||
function FillOrKillFailedError(
|
||||
bytes32 orderHash,
|
||||
uint256 takerTokenFilledAmount,
|
||||
uint256 takerTokenFillAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("FillOrKillFailedError(bytes32,uint256,uint256)")),
|
||||
orderHash,
|
||||
takerTokenFilledAmount,
|
||||
takerTokenFillAmount
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyOrderMakerAllowed(
|
||||
bytes32 orderHash,
|
||||
address sender,
|
||||
address maker
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
bytes4(keccak256("OnlyOrderMakerAllowed(bytes32,address,address)")),
|
||||
orderHash,
|
||||
sender,
|
||||
maker
|
||||
);
|
||||
}
|
||||
}
|
@@ -58,8 +58,8 @@ contract FeeCollector is AuthorizableV06 {
|
||||
onlyAuthorized
|
||||
{
|
||||
// Leave 1 wei behind to avoid expensive zero-->non-zero state change.
|
||||
if (address(this).balance > 1) {
|
||||
weth.deposit{value: address(this).balance - 1}();
|
||||
if (address(this).balance > 0) {
|
||||
weth.deposit{value: address(this).balance}();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
74
contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol
vendored
Normal file
74
contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
interface ILiquidityProviderSandbox {
|
||||
|
||||
/// @dev Calls `sellTokenForToken` on the given `provider` contract to
|
||||
/// trigger a trade.
|
||||
/// @param provider The address of the on-chain liquidity provider.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForToken(
|
||||
address provider,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Calls `sellEthForToken` on the given `provider` contract to
|
||||
/// trigger a trade.
|
||||
/// @param provider The address of the on-chain liquidity provider.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellEthForToken(
|
||||
address provider,
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Calls `sellTokenForEth` on the given `provider` contract to
|
||||
/// trigger a trade.
|
||||
/// @param provider The address of the on-chain liquidity provider.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForEth(
|
||||
address provider,
|
||||
address inputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external;
|
||||
}
|
139
contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol
vendored
Normal file
139
contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibOwnableRichErrorsV06.sol";
|
||||
import "../vendor/ILiquidityProvider.sol";
|
||||
import "../vendor/v3/IERC20Bridge.sol";
|
||||
import "./ILiquidityProviderSandbox.sol";
|
||||
|
||||
|
||||
/// @dev A permissionless contract through which the ZeroEx contract can
|
||||
/// safely trigger a trade on an external `ILiquidityProvider` contract.
|
||||
contract LiquidityProviderSandbox is
|
||||
ILiquidityProviderSandbox
|
||||
{
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
/// @dev Store the owner as an immutable.
|
||||
address public immutable owner;
|
||||
|
||||
constructor(address owner_)
|
||||
public
|
||||
{
|
||||
owner = owner_;
|
||||
}
|
||||
|
||||
/// @dev Allows only the (immutable) owner to call a function.
|
||||
modifier onlyOwner() virtual {
|
||||
if (msg.sender != owner) {
|
||||
LibOwnableRichErrorsV06.OnlyOwnerError(
|
||||
msg.sender,
|
||||
owner
|
||||
).rrevert();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Calls `sellTokenForToken` on the given `provider` contract to
|
||||
/// trigger a trade.
|
||||
/// @param provider The address of the on-chain liquidity provider.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForToken(
|
||||
address provider,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
override
|
||||
{
|
||||
try ILiquidityProvider(provider).sellTokenForToken(
|
||||
inputToken,
|
||||
outputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
auxiliaryData
|
||||
) {} catch {
|
||||
IERC20Bridge(provider).bridgeTransferFrom(
|
||||
outputToken,
|
||||
provider,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls `sellEthForToken` on the given `provider` contract to
|
||||
/// trigger a trade.
|
||||
/// @param provider The address of the on-chain liquidity provider.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellEthForToken(
|
||||
address provider,
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
override
|
||||
{
|
||||
ILiquidityProvider(provider).sellEthForToken(
|
||||
outputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Calls `sellTokenForEth` on the given `provider` contract to
|
||||
/// trigger a trade.
|
||||
/// @param provider The address of the on-chain liquidity provider.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
function executeSellTokenForEth(
|
||||
address provider,
|
||||
address inputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
override
|
||||
{
|
||||
ILiquidityProvider(provider).sellTokenForEth(
|
||||
inputToken,
|
||||
payable(recipient),
|
||||
minBuyAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
}
|
@@ -22,45 +22,30 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
/// @dev Feature to swap directly with an on-chain liquidity provider.
|
||||
interface ILiquidityProviderFeature {
|
||||
event LiquidityProviderForMarketUpdated(
|
||||
address indexed xAsset,
|
||||
address indexed yAsset,
|
||||
address providerAddress
|
||||
);
|
||||
|
||||
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
|
||||
/// at the given `provider` address.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param provider The address of the on-chain liquidity provider
|
||||
/// to trade with.
|
||||
/// @param recipient The recipient of the bought tokens. If equal to
|
||||
/// address(0), `msg.sender` is assumed to be the recipient.
|
||||
/// @param sellAmount The amount of `inputToken` to sell.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to
|
||||
/// buy. Reverts if this amount is not satisfied.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellToLiquidityProvider(
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
address payable recipient,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address payable provider,
|
||||
address recipient,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount);
|
||||
|
||||
/// @dev Sets address of the liquidity provider for a market given
|
||||
/// (xAsset, yAsset).
|
||||
/// @param xAsset First asset managed by the liquidity provider.
|
||||
/// @param yAsset Second asset managed by the liquidity provider.
|
||||
/// @param providerAddress Address of the liquidity provider.
|
||||
function setLiquidityProviderForMarket(
|
||||
address xAsset,
|
||||
address yAsset,
|
||||
address providerAddress
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Returns the address of the liquidity provider for a market given
|
||||
/// (xAsset, yAsset), or reverts if pool does not exist.
|
||||
/// @param xAsset First asset managed by the liquidity provider.
|
||||
/// @param yAsset Second asset managed by the liquidity provider.
|
||||
/// @return providerAddress Address of the liquidity provider.
|
||||
function getLiquidityProviderForMarket(
|
||||
address xAsset,
|
||||
address yAsset
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (address providerAddress);
|
||||
}
|
||||
|
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "./libs/LibSignature.sol";
|
||||
import "./libs/LibNativeOrder.sol";
|
||||
|
||||
|
||||
/// @dev Feature for interacting with limit orders.
|
||||
interface INativeOrdersFeature {
|
||||
|
||||
/// @dev Emitted whenever a `LimitOrder` is filled.
|
||||
/// @param orderHash The canonical hash of the order.
|
||||
/// @param maker The maker of the order.
|
||||
/// @param taker The taker of the order.
|
||||
/// @param feeRecipient Fee recipient of the order.
|
||||
/// @param takerTokenFilledAmount How much taker token was filled.
|
||||
/// @param makerTokenFilledAmount How much maker token was filled.
|
||||
/// @param protocolFeePaid How much protocol fee was paid.
|
||||
/// @param pool The fee pool associated with this order.
|
||||
event LimitOrderFilled(
|
||||
bytes32 orderHash,
|
||||
address maker,
|
||||
address taker,
|
||||
address feeRecipient,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint128 takerTokenFilledAmount,
|
||||
uint128 makerTokenFilledAmount,
|
||||
uint128 takerTokenFeeFilledAmount,
|
||||
uint256 protocolFeePaid,
|
||||
bytes32 pool
|
||||
);
|
||||
|
||||
/// @dev Emitted whenever an `RfqOrder` is filled.
|
||||
/// @param orderHash The canonical hash of the order.
|
||||
/// @param maker The maker of the order.
|
||||
/// @param taker The taker of the order.
|
||||
/// @param takerTokenFilledAmount How much taker token was filled.
|
||||
/// @param makerTokenFilledAmount How much maker token was filled.
|
||||
/// @param protocolFeePaid How much protocol fee was paid.
|
||||
/// @param pool The fee pool associated with this order.
|
||||
event RfqOrderFilled(
|
||||
bytes32 orderHash,
|
||||
address maker,
|
||||
address taker,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint128 takerTokenFilledAmount,
|
||||
uint128 makerTokenFilledAmount,
|
||||
uint256 protocolFeePaid,
|
||||
bytes32 pool
|
||||
);
|
||||
|
||||
/// @dev Emitted whenever a limit or RFQ order is cancelled.
|
||||
/// @param orderHash The canonical hash of the order.
|
||||
/// @param maker The order maker.
|
||||
event OrderCancelled(
|
||||
bytes32 orderHash,
|
||||
address maker
|
||||
);
|
||||
|
||||
/// @dev Emitted whenever limit or RFQ orders are cancelled by pair by a maker.
|
||||
/// @param maker The maker of the order.
|
||||
/// @param makerToken The maker token in a pair for the orders cancelled.
|
||||
/// @param takerToken The taker token in a pair for the orders cancelled.
|
||||
/// @param minValidSalt The new minimum valid salt an order with this pair must
|
||||
/// have.
|
||||
event PairOrdersCancelled(
|
||||
address maker,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint256 minValidSalt
|
||||
);
|
||||
|
||||
/// @dev Transfers protocol fees from the `FeeCollector` pools into
|
||||
/// the staking contract.
|
||||
/// @param poolIds Staking pool IDs
|
||||
function transferProtocolFeesForPools(bytes32[] calldata poolIds)
|
||||
external;
|
||||
|
||||
/// @dev Fill a limit order. The taker and sender will be the caller.
|
||||
/// @param order The limit order. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// the caller.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token amount to fill this order with.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillLimitOrder(
|
||||
LibNativeOrder.LimitOrder calldata order,
|
||||
LibSignature.Signature calldata signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
|
||||
|
||||
/// @dev Fill an RFQ order for up to `takerTokenFillAmount` taker tokens.
|
||||
/// The taker will be the caller. ETH should be attached to pay the
|
||||
/// protocol fee.
|
||||
/// @param order The RFQ order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token amount to fill this order with.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillRfqOrder(
|
||||
LibNativeOrder.RfqOrder calldata order,
|
||||
LibSignature.Signature calldata signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
|
||||
|
||||
/// @dev Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens.
|
||||
/// The taker will be the caller. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// the caller.
|
||||
/// @param order The limit order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount How much taker token to fill this order with.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillOrKillLimitOrder(
|
||||
LibNativeOrder.LimitOrder calldata order,
|
||||
LibSignature.Signature calldata signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint128 makerTokenFilledAmount);
|
||||
|
||||
/// @dev Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens.
|
||||
/// The taker will be the caller. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// the caller.
|
||||
/// @param order The RFQ order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount How much taker token to fill this order with.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillOrKillRfqOrder(
|
||||
LibNativeOrder.RfqOrder calldata order,
|
||||
LibSignature.Signature calldata signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint128 makerTokenFilledAmount);
|
||||
|
||||
/// @dev Fill a limit order. Internal variant. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// `msg.sender` (not `sender`).
|
||||
/// @param order The limit order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token to fill this order with.
|
||||
/// @param taker The order taker.
|
||||
/// @param sender The order sender.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function _fillLimitOrder(
|
||||
LibNativeOrder.LimitOrder calldata order,
|
||||
LibSignature.Signature calldata signature,
|
||||
uint128 takerTokenFillAmount,
|
||||
address taker,
|
||||
address sender
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
|
||||
|
||||
/// @dev Fill an RFQ order. Internal variant. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// `msg.sender` (not `sender`).
|
||||
/// @param order The RFQ order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token to fill this order with.
|
||||
/// @param taker The order taker.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function _fillRfqOrder(
|
||||
LibNativeOrder.RfqOrder calldata order,
|
||||
LibSignature.Signature calldata signature,
|
||||
uint128 takerTokenFillAmount,
|
||||
address taker
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
|
||||
|
||||
/// @dev Cancel a single limit order. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param order The limit order.
|
||||
function cancelLimitOrder(LibNativeOrder.LimitOrder calldata order)
|
||||
external;
|
||||
|
||||
/// @dev Cancel a single RFQ order. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param order The RFQ order.
|
||||
function cancelRfqOrder(LibNativeOrder.RfqOrder calldata order)
|
||||
external;
|
||||
|
||||
/// @dev Cancel multiple limit orders. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param orders The limit orders.
|
||||
function batchCancelLimitOrders(LibNativeOrder.LimitOrder[] calldata orders)
|
||||
external;
|
||||
|
||||
/// @dev Cancel multiple RFQ orders. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param orders The RFQ orders.
|
||||
function batchCancelRfqOrders(LibNativeOrder.RfqOrder[] calldata orders)
|
||||
external;
|
||||
|
||||
/// @dev Cancel all limit orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerToken The maker token.
|
||||
/// @param takerToken The taker token.
|
||||
/// @param minValidSalt The new minimum valid salt.
|
||||
function cancelPairLimitOrders(
|
||||
IERC20TokenV06 makerToken,
|
||||
IERC20TokenV06 takerToken,
|
||||
uint256 minValidSalt
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Cancel all limit orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerTokens The maker tokens.
|
||||
/// @param takerTokens The taker tokens.
|
||||
/// @param minValidSalts The new minimum valid salts.
|
||||
function batchCancelPairLimitOrders(
|
||||
IERC20TokenV06[] calldata makerTokens,
|
||||
IERC20TokenV06[] calldata takerTokens,
|
||||
uint256[] calldata minValidSalts
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerToken The maker token.
|
||||
/// @param takerToken The taker token.
|
||||
/// @param minValidSalt The new minimum valid salt.
|
||||
function cancelPairRfqOrders(
|
||||
IERC20TokenV06 makerToken,
|
||||
IERC20TokenV06 takerToken,
|
||||
uint256 minValidSalt
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerTokens The maker tokens.
|
||||
/// @param takerTokens The taker tokens.
|
||||
/// @param minValidSalts The new minimum valid salts.
|
||||
function batchCancelPairRfqOrders(
|
||||
IERC20TokenV06[] calldata makerTokens,
|
||||
IERC20TokenV06[] calldata takerTokens,
|
||||
uint256[] calldata minValidSalts
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Get the order info for a limit order.
|
||||
/// @param order The limit order.
|
||||
/// @return orderInfo Info about the order.
|
||||
function getLimitOrderInfo(LibNativeOrder.LimitOrder calldata order)
|
||||
external
|
||||
view
|
||||
returns (LibNativeOrder.OrderInfo memory orderInfo);
|
||||
|
||||
/// @dev Get the order info for an RFQ order.
|
||||
/// @param order The RFQ order.
|
||||
/// @return orderInfo Info about the order.
|
||||
function getRfqOrderInfo(LibNativeOrder.RfqOrder calldata order)
|
||||
external
|
||||
view
|
||||
returns (LibNativeOrder.OrderInfo memory orderInfo);
|
||||
|
||||
/// @dev Get the canonical hash of a limit order.
|
||||
/// @param order The limit order.
|
||||
/// @return orderHash The order hash.
|
||||
function getLimitOrderHash(LibNativeOrder.LimitOrder calldata order)
|
||||
external
|
||||
view
|
||||
returns (bytes32 orderHash);
|
||||
|
||||
/// @dev Get the canonical hash of an RFQ order.
|
||||
/// @param order The RFQ order.
|
||||
/// @return orderHash The order hash.
|
||||
function getRfqOrderHash(LibNativeOrder.RfqOrder calldata order)
|
||||
external
|
||||
view
|
||||
returns (bytes32 orderHash);
|
||||
|
||||
/// @dev Get the protocol fee multiplier. This should be multiplied by the
|
||||
/// gas price to arrive at the required protocol fee to fill a native order.
|
||||
/// @return multiplier The protocol fee multiplier.
|
||||
function getProtocolFeeMultiplier()
|
||||
external
|
||||
view
|
||||
returns (uint32 multiplier);
|
||||
|
||||
}
|
@@ -57,4 +57,12 @@ interface ISimpleFunctionRegistryFeature {
|
||||
external
|
||||
view
|
||||
returns (address impl);
|
||||
|
||||
/// @dev Get the implementation contract of a registered function.
|
||||
/// @param selector The function selector.
|
||||
/// @return impl The implementation contract address.
|
||||
function getFunctionImplementation(bytes4 selector)
|
||||
external
|
||||
view
|
||||
returns (address impl);
|
||||
}
|
||||
|
@@ -20,15 +20,13 @@ pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
import "../errors/LibLiquidityProviderRichErrors.sol";
|
||||
import "../external/ILiquidityProviderSandbox.sol";
|
||||
import "../external/LiquidityProviderSandbox.sol";
|
||||
import "../fixins/FixinCommon.sol";
|
||||
import "../migrations/LibMigrate.sol";
|
||||
import "../storage/LibLiquidityProviderStorage.sol";
|
||||
import "../vendor/v3/IERC20Bridge.sol";
|
||||
import "./IFeature.sol";
|
||||
import "./ILiquidityProviderFeature.sol";
|
||||
import "./libs/LibTokenSpender.sol";
|
||||
@@ -39,27 +37,34 @@ contract LiquidityProviderFeature is
|
||||
ILiquidityProviderFeature,
|
||||
FixinCommon
|
||||
{
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "LiquidityProviderFeature";
|
||||
/// @dev Version of this feature.
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 1);
|
||||
|
||||
/// @dev ETH pseudo-token address.
|
||||
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev The WETH contract address.
|
||||
IEtherTokenV06 public immutable weth;
|
||||
/// @dev The sandbox contract address.
|
||||
ILiquidityProviderSandbox public immutable sandbox;
|
||||
|
||||
/// @dev Store the WETH address in an immutable.
|
||||
/// @param weth_ The weth token.
|
||||
constructor(IEtherTokenV06 weth_)
|
||||
/// @dev Event for data pipeline.
|
||||
event LiquidityProviderSwap(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address provider,
|
||||
address recipient
|
||||
);
|
||||
|
||||
constructor(LiquidityProviderSandbox sandbox_)
|
||||
public
|
||||
FixinCommon()
|
||||
{
|
||||
weth = weth_;
|
||||
sandbox = sandbox_;
|
||||
}
|
||||
|
||||
/// @dev Initialize and register this feature.
|
||||
@@ -70,131 +75,103 @@ contract LiquidityProviderFeature is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
_registerFeatureFunction(this.sellToLiquidityProvider.selector);
|
||||
_registerFeatureFunction(this.setLiquidityProviderForMarket.selector);
|
||||
_registerFeatureFunction(this.getLiquidityProviderForMarket.selector);
|
||||
return LibMigrate.MIGRATE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
|
||||
/// at the given `provider` address.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param provider The address of the on-chain liquidity provider
|
||||
/// to trade with.
|
||||
/// @param recipient The recipient of the bought tokens. If equal to
|
||||
/// address(0), `msg.sender` is assumed to be the recipient.
|
||||
/// @param sellAmount The amount of `inputToken` to sell.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to
|
||||
/// buy. Reverts if this amount is not satisfied.
|
||||
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellToLiquidityProvider(
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
address payable recipient,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address payable provider,
|
||||
address recipient,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
override
|
||||
payable
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
address providerAddress = getLiquidityProviderForMarket(makerToken, takerToken);
|
||||
if (recipient == address(0)) {
|
||||
recipient = msg.sender;
|
||||
}
|
||||
|
||||
if (takerToken == ETH_TOKEN_ADDRESS) {
|
||||
// Wrap ETH.
|
||||
weth.deposit{value: sellAmount}();
|
||||
weth.transfer(providerAddress, sellAmount);
|
||||
if (inputToken == ETH_TOKEN_ADDRESS) {
|
||||
provider.transfer(sellAmount);
|
||||
} else {
|
||||
LibTokenSpender.spendERC20Tokens(
|
||||
IERC20TokenV06(takerToken),
|
||||
IERC20TokenV06(inputToken),
|
||||
msg.sender,
|
||||
providerAddress,
|
||||
sellAmount
|
||||
provider,
|
||||
sellAmount,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if (makerToken == ETH_TOKEN_ADDRESS) {
|
||||
uint256 balanceBefore = weth.balanceOf(address(this));
|
||||
IERC20Bridge(providerAddress).bridgeTransferFrom(
|
||||
address(weth),
|
||||
address(0),
|
||||
address(this),
|
||||
minBuyAmount,
|
||||
""
|
||||
);
|
||||
boughtAmount = weth.balanceOf(address(this)).safeSub(balanceBefore);
|
||||
// Unwrap wETH and send ETH to recipient.
|
||||
weth.withdraw(boughtAmount);
|
||||
recipient.transfer(boughtAmount);
|
||||
} else {
|
||||
uint256 balanceBefore = IERC20TokenV06(makerToken).balanceOf(recipient);
|
||||
IERC20Bridge(providerAddress).bridgeTransferFrom(
|
||||
makerToken,
|
||||
address(0),
|
||||
if (inputToken == ETH_TOKEN_ADDRESS) {
|
||||
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
|
||||
sandbox.executeSellEthForToken(
|
||||
provider,
|
||||
outputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
""
|
||||
auxiliaryData
|
||||
);
|
||||
boughtAmount = IERC20TokenV06(makerToken).balanceOf(recipient).safeSub(balanceBefore);
|
||||
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
|
||||
} else if (outputToken == ETH_TOKEN_ADDRESS) {
|
||||
uint256 balanceBefore = recipient.balance;
|
||||
sandbox.executeSellTokenForEth(
|
||||
provider,
|
||||
inputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
boughtAmount = recipient.balance.safeSub(balanceBefore);
|
||||
} else {
|
||||
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
|
||||
sandbox.executeSellTokenForToken(
|
||||
provider,
|
||||
inputToken,
|
||||
outputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
|
||||
}
|
||||
|
||||
if (boughtAmount < minBuyAmount) {
|
||||
LibLiquidityProviderRichErrors.LiquidityProviderIncompleteSellError(
|
||||
providerAddress,
|
||||
makerToken,
|
||||
takerToken,
|
||||
provider,
|
||||
outputToken,
|
||||
inputToken,
|
||||
sellAmount,
|
||||
boughtAmount,
|
||||
minBuyAmount
|
||||
).rrevert();
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sets address of the liquidity provider for a market given
|
||||
/// (xAsset, yAsset).
|
||||
/// @param xAsset First asset managed by the liquidity provider.
|
||||
/// @param yAsset Second asset managed by the liquidity provider.
|
||||
/// @param providerAddress Address of the liquidity provider.
|
||||
function setLiquidityProviderForMarket(
|
||||
address xAsset,
|
||||
address yAsset,
|
||||
address providerAddress
|
||||
)
|
||||
external
|
||||
override
|
||||
onlyOwner
|
||||
{
|
||||
LibLiquidityProviderStorage.getStorage()
|
||||
.addressBook[xAsset][yAsset] = providerAddress;
|
||||
LibLiquidityProviderStorage.getStorage()
|
||||
.addressBook[yAsset][xAsset] = providerAddress;
|
||||
emit LiquidityProviderForMarketUpdated(
|
||||
xAsset,
|
||||
yAsset,
|
||||
providerAddress
|
||||
emit LiquidityProviderSwap(
|
||||
inputToken,
|
||||
outputToken,
|
||||
sellAmount,
|
||||
boughtAmount,
|
||||
provider,
|
||||
recipient
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Returns the address of the liquidity provider for a market given
|
||||
/// (xAsset, yAsset), or reverts if pool does not exist.
|
||||
/// @param xAsset First asset managed by the liquidity provider.
|
||||
/// @param yAsset Second asset managed by the liquidity provider.
|
||||
/// @return providerAddress Address of the liquidity provider.
|
||||
function getLiquidityProviderForMarket(
|
||||
address xAsset,
|
||||
address yAsset
|
||||
)
|
||||
public
|
||||
view
|
||||
override
|
||||
returns (address providerAddress)
|
||||
{
|
||||
if (xAsset == ETH_TOKEN_ADDRESS) {
|
||||
providerAddress = LibLiquidityProviderStorage.getStorage()
|
||||
.addressBook[address(weth)][yAsset];
|
||||
} else if (yAsset == ETH_TOKEN_ADDRESS) {
|
||||
providerAddress = LibLiquidityProviderStorage.getStorage()
|
||||
.addressBook[xAsset][address(weth)];
|
||||
} else {
|
||||
providerAddress = LibLiquidityProviderStorage.getStorage()
|
||||
.addressBook[xAsset][yAsset];
|
||||
}
|
||||
if (providerAddress == address(0)) {
|
||||
LibLiquidityProviderRichErrors.NoLiquidityProviderForMarketError(
|
||||
xAsset,
|
||||
yAsset
|
||||
).rrevert();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -78,7 +78,7 @@ contract MetaTransactionsFeature is
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "MetaTransactions";
|
||||
/// @dev Version of this feature.
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
|
||||
/// @dev EIP712 typehash of the `MetaTransactionData` struct.
|
||||
bytes32 public immutable MTX_EIP712_TYPEHASH = keccak256(
|
||||
"MetaTransactionData("
|
||||
@@ -283,7 +283,8 @@ contract MetaTransactionsFeature is
|
||||
mtx.feeToken,
|
||||
mtx.signer,
|
||||
sender,
|
||||
mtx.feeAmount
|
||||
mtx.feeAmount,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
987
contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol
Normal file
987
contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol
Normal file
@@ -0,0 +1,987 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
|
||||
import "../fixins/FixinCommon.sol";
|
||||
import "../fixins/FixinProtocolFees.sol";
|
||||
import "../fixins/FixinEIP712.sol";
|
||||
import "../errors/LibNativeOrdersRichErrors.sol";
|
||||
import "../migrations/LibMigrate.sol";
|
||||
import "../storage/LibNativeOrdersStorage.sol";
|
||||
import "../vendor/v3/IStaking.sol";
|
||||
import "./libs/LibTokenSpender.sol";
|
||||
import "./libs/LibSignature.sol";
|
||||
import "./libs/LibNativeOrder.sol";
|
||||
import "./INativeOrdersFeature.sol";
|
||||
import "./IFeature.sol";
|
||||
|
||||
|
||||
/// @dev Feature for interacting with limit orders.
|
||||
contract NativeOrdersFeature is
|
||||
IFeature,
|
||||
INativeOrdersFeature,
|
||||
FixinCommon,
|
||||
FixinProtocolFees,
|
||||
FixinEIP712
|
||||
{
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibSafeMathV06 for uint128;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
/// @dev Params for `_settleOrder()`.
|
||||
struct SettleOrderInfo {
|
||||
// Order hash.
|
||||
bytes32 orderHash;
|
||||
// Maker of the order.
|
||||
address maker;
|
||||
// Taker of the order.
|
||||
address taker;
|
||||
// Maker token.
|
||||
IERC20TokenV06 makerToken;
|
||||
// Taker token.
|
||||
IERC20TokenV06 takerToken;
|
||||
// Maker token amount.
|
||||
uint128 makerAmount;
|
||||
// Taker token amount.
|
||||
uint128 takerAmount;
|
||||
// Maximum taker token amount to fill.
|
||||
uint128 takerTokenFillAmount;
|
||||
// How much taker token amount has already been filled in this order.
|
||||
uint128 takerTokenFilledAmount;
|
||||
}
|
||||
|
||||
/// @dev Params for `_fillLimitOrderPrivate()`
|
||||
struct FillLimitOrderPrivateParams {
|
||||
// The limit order.
|
||||
LibNativeOrder.LimitOrder order;
|
||||
// The order signature.
|
||||
LibSignature.Signature signature;
|
||||
// Maximum taker token to fill this order with.
|
||||
uint128 takerTokenFillAmount;
|
||||
// The order taker.
|
||||
address taker;
|
||||
// The order sender.
|
||||
address sender;
|
||||
}
|
||||
|
||||
// @dev Fill results returned by `_fillLimitOrderPrivate()` and
|
||||
/// `_fillRfqOrderPrivate()`.
|
||||
struct FillNativeOrderResults {
|
||||
uint256 ethProtocolFeePaid;
|
||||
uint128 takerTokenFilledAmount;
|
||||
uint128 makerTokenFilledAmount;
|
||||
uint128 takerTokenFeeFilledAmount;
|
||||
}
|
||||
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "LimitOrders";
|
||||
/// @dev Version of this feature.
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
|
||||
/// @dev Highest bit of a uint256, used to flag cancelled orders.
|
||||
uint256 private constant HIGH_BIT = 1 << 255;
|
||||
|
||||
constructor(
|
||||
address zeroExAddress,
|
||||
IEtherTokenV06 weth,
|
||||
IStaking staking,
|
||||
uint32 protocolFeeMultiplier
|
||||
)
|
||||
public
|
||||
FixinEIP712(zeroExAddress)
|
||||
FixinProtocolFees(weth, staking, protocolFeeMultiplier)
|
||||
{
|
||||
// solhint-disable no-empty-blocks
|
||||
}
|
||||
|
||||
/// @dev Initialize and register this feature.
|
||||
/// Should be delegatecalled by `Migrate.migrate()`.
|
||||
/// @return success `LibMigrate.SUCCESS` on success.
|
||||
function migrate()
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
_registerFeatureFunction(this.transferProtocolFeesForPools.selector);
|
||||
_registerFeatureFunction(this.fillLimitOrder.selector);
|
||||
_registerFeatureFunction(this.fillRfqOrder.selector);
|
||||
_registerFeatureFunction(this.fillOrKillLimitOrder.selector);
|
||||
_registerFeatureFunction(this.fillOrKillRfqOrder.selector);
|
||||
_registerFeatureFunction(this._fillLimitOrder.selector);
|
||||
_registerFeatureFunction(this._fillRfqOrder.selector);
|
||||
_registerFeatureFunction(this.cancelLimitOrder.selector);
|
||||
_registerFeatureFunction(this.cancelRfqOrder.selector);
|
||||
_registerFeatureFunction(this.batchCancelLimitOrders.selector);
|
||||
_registerFeatureFunction(this.batchCancelRfqOrders.selector);
|
||||
_registerFeatureFunction(this.cancelPairLimitOrders.selector);
|
||||
_registerFeatureFunction(this.batchCancelPairLimitOrders.selector);
|
||||
_registerFeatureFunction(this.cancelPairRfqOrders.selector);
|
||||
_registerFeatureFunction(this.batchCancelPairRfqOrders.selector);
|
||||
_registerFeatureFunction(this.getLimitOrderInfo.selector);
|
||||
_registerFeatureFunction(this.getRfqOrderInfo.selector);
|
||||
_registerFeatureFunction(this.getLimitOrderHash.selector);
|
||||
_registerFeatureFunction(this.getRfqOrderHash.selector);
|
||||
_registerFeatureFunction(this.getProtocolFeeMultiplier.selector);
|
||||
return LibMigrate.MIGRATE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev Transfers protocol fees from the `FeeCollector` pools into
|
||||
/// the staking contract.
|
||||
/// @param poolIds Staking pool IDs
|
||||
function transferProtocolFeesForPools(bytes32[] calldata poolIds)
|
||||
external
|
||||
override
|
||||
{
|
||||
for (uint256 i = 0; i < poolIds.length; ++i) {
|
||||
_transferFeesForPool(poolIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Fill a limit order. The taker and sender will be the caller.
|
||||
/// @param order The limit order. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// the caller.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token amount to fill this order with.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillLimitOrder(
|
||||
LibNativeOrder.LimitOrder memory order,
|
||||
LibSignature.Signature memory signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
public
|
||||
override
|
||||
payable
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
|
||||
{
|
||||
FillNativeOrderResults memory results =
|
||||
_fillLimitOrderPrivate(FillLimitOrderPrivateParams({
|
||||
order: order,
|
||||
signature: signature,
|
||||
takerTokenFillAmount: takerTokenFillAmount,
|
||||
taker: msg.sender,
|
||||
sender: msg.sender
|
||||
}));
|
||||
_refundExcessProtocolFeeToSender(results.ethProtocolFeePaid);
|
||||
(takerTokenFilledAmount, makerTokenFilledAmount) = (
|
||||
results.takerTokenFilledAmount,
|
||||
results.makerTokenFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Fill an RFQ order for up to `takerTokenFillAmount` taker tokens.
|
||||
/// The taker will be the caller. ETH should be attached to pay the
|
||||
/// protocol fee.
|
||||
/// @param order The RFQ order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token amount to fill this order with.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillRfqOrder(
|
||||
LibNativeOrder.RfqOrder memory order,
|
||||
LibSignature.Signature memory signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
public
|
||||
override
|
||||
payable
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
|
||||
{
|
||||
FillNativeOrderResults memory results =
|
||||
_fillRfqOrderPrivate(
|
||||
order,
|
||||
signature,
|
||||
takerTokenFillAmount,
|
||||
msg.sender
|
||||
);
|
||||
_refundExcessProtocolFeeToSender(results.ethProtocolFeePaid);
|
||||
(takerTokenFilledAmount, makerTokenFilledAmount) = (
|
||||
results.takerTokenFilledAmount,
|
||||
results.makerTokenFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens.
|
||||
/// The taker will be the caller. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// the caller.
|
||||
/// @param order The limit order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount How much taker token to fill this order with.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillOrKillLimitOrder(
|
||||
LibNativeOrder.LimitOrder memory order,
|
||||
LibSignature.Signature memory signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
public
|
||||
override
|
||||
payable
|
||||
returns (uint128 makerTokenFilledAmount)
|
||||
{
|
||||
FillNativeOrderResults memory results =
|
||||
_fillLimitOrderPrivate(FillLimitOrderPrivateParams({
|
||||
order: order,
|
||||
signature: signature,
|
||||
takerTokenFillAmount: takerTokenFillAmount,
|
||||
taker: msg.sender,
|
||||
sender: msg.sender
|
||||
}));
|
||||
// Must have filled exactly the amount requested.
|
||||
if (results.takerTokenFilledAmount < takerTokenFillAmount) {
|
||||
LibNativeOrdersRichErrors.FillOrKillFailedError(
|
||||
getLimitOrderHash(order),
|
||||
results.takerTokenFilledAmount,
|
||||
takerTokenFillAmount
|
||||
).rrevert();
|
||||
}
|
||||
_refundExcessProtocolFeeToSender(results.ethProtocolFeePaid);
|
||||
makerTokenFilledAmount = results.makerTokenFilledAmount;
|
||||
}
|
||||
|
||||
/// @dev Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens.
|
||||
/// The taker will be the caller. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// the caller.
|
||||
/// @param order The RFQ order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount How much taker token to fill this order with.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function fillOrKillRfqOrder(
|
||||
LibNativeOrder.RfqOrder memory order,
|
||||
LibSignature.Signature memory signature,
|
||||
uint128 takerTokenFillAmount
|
||||
)
|
||||
public
|
||||
override
|
||||
payable
|
||||
returns (uint128 makerTokenFilledAmount)
|
||||
{
|
||||
FillNativeOrderResults memory results =
|
||||
_fillRfqOrderPrivate(
|
||||
order,
|
||||
signature,
|
||||
takerTokenFillAmount,
|
||||
msg.sender
|
||||
);
|
||||
// Must have filled exactly the amount requested.
|
||||
if (results.takerTokenFilledAmount < takerTokenFillAmount) {
|
||||
LibNativeOrdersRichErrors.FillOrKillFailedError(
|
||||
getRfqOrderHash(order),
|
||||
results.takerTokenFilledAmount,
|
||||
takerTokenFillAmount
|
||||
).rrevert();
|
||||
}
|
||||
_refundExcessProtocolFeeToSender(results.ethProtocolFeePaid);
|
||||
makerTokenFilledAmount = results.makerTokenFilledAmount;
|
||||
}
|
||||
|
||||
/// @dev Fill a limit order. Internal variant. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// `msg.sender` (not `sender`).
|
||||
/// @param order The limit order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token to fill this order with.
|
||||
/// @param taker The order taker.
|
||||
/// @param sender The order sender.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function _fillLimitOrder(
|
||||
LibNativeOrder.LimitOrder memory order,
|
||||
LibSignature.Signature memory signature,
|
||||
uint128 takerTokenFillAmount,
|
||||
address taker,
|
||||
address sender
|
||||
)
|
||||
public
|
||||
override
|
||||
payable
|
||||
onlySelf
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
|
||||
{
|
||||
FillNativeOrderResults memory results =
|
||||
_fillLimitOrderPrivate(FillLimitOrderPrivateParams({
|
||||
order: order,
|
||||
signature: signature,
|
||||
takerTokenFillAmount: takerTokenFillAmount,
|
||||
taker: taker,
|
||||
sender: sender
|
||||
}));
|
||||
_refundExcessProtocolFeeToSender(results.ethProtocolFeePaid);
|
||||
(takerTokenFilledAmount, makerTokenFilledAmount) = (
|
||||
results.takerTokenFilledAmount,
|
||||
results.makerTokenFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Fill an RFQ order. Internal variant. ETH protocol fees can be
|
||||
/// attached to this call. Any unspent ETH will be refunded to
|
||||
/// `msg.sender` (not `sender`).
|
||||
/// @param order The RFQ order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token to fill this order with.
|
||||
/// @param taker The order taker.
|
||||
/// @return takerTokenFilledAmount How much maker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function _fillRfqOrder(
|
||||
LibNativeOrder.RfqOrder memory order,
|
||||
LibSignature.Signature memory signature,
|
||||
uint128 takerTokenFillAmount,
|
||||
address taker
|
||||
)
|
||||
public
|
||||
override
|
||||
payable
|
||||
onlySelf
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
|
||||
{
|
||||
FillNativeOrderResults memory results =
|
||||
_fillRfqOrderPrivate(
|
||||
order,
|
||||
signature,
|
||||
takerTokenFillAmount,
|
||||
taker
|
||||
);
|
||||
_refundExcessProtocolFeeToSender(results.ethProtocolFeePaid);
|
||||
(takerTokenFilledAmount, makerTokenFilledAmount) = (
|
||||
results.takerTokenFilledAmount,
|
||||
results.makerTokenFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Cancel a single limit order. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param order The limit order.
|
||||
function cancelLimitOrder(LibNativeOrder.LimitOrder memory order)
|
||||
public
|
||||
override
|
||||
{
|
||||
bytes32 orderHash = getLimitOrderHash(order);
|
||||
if (msg.sender != order.maker) {
|
||||
LibNativeOrdersRichErrors.OnlyOrderMakerAllowed(
|
||||
orderHash,
|
||||
msg.sender,
|
||||
order.maker
|
||||
).rrevert();
|
||||
}
|
||||
_cancelOrderHash(orderHash, order.maker);
|
||||
}
|
||||
|
||||
/// @dev Cancel a single RFQ order. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param order The RFQ order.
|
||||
function cancelRfqOrder(LibNativeOrder.RfqOrder memory order)
|
||||
public
|
||||
override
|
||||
{
|
||||
bytes32 orderHash = getRfqOrderHash(order);
|
||||
if (msg.sender != order.maker) {
|
||||
LibNativeOrdersRichErrors.OnlyOrderMakerAllowed(
|
||||
orderHash,
|
||||
msg.sender,
|
||||
order.maker
|
||||
).rrevert();
|
||||
}
|
||||
_cancelOrderHash(orderHash, order.maker);
|
||||
}
|
||||
|
||||
/// @dev Cancel multiple limit orders. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param orders The limit orders.
|
||||
function batchCancelLimitOrders(LibNativeOrder.LimitOrder[] memory orders)
|
||||
public
|
||||
override
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; ++i) {
|
||||
cancelLimitOrder(orders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Cancel multiple RFQ orders. The caller must be the maker.
|
||||
/// Silently succeeds if the order has already been cancelled.
|
||||
/// @param orders The RFQ orders.
|
||||
function batchCancelRfqOrders(LibNativeOrder.RfqOrder[] memory orders)
|
||||
public
|
||||
override
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; ++i) {
|
||||
cancelRfqOrder(orders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Cancel all limit orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerToken The maker token.
|
||||
/// @param takerToken The taker token.
|
||||
/// @param minValidSalt The new minimum valid salt.
|
||||
function cancelPairLimitOrders(
|
||||
IERC20TokenV06 makerToken,
|
||||
IERC20TokenV06 takerToken,
|
||||
uint256 minValidSalt
|
||||
)
|
||||
public
|
||||
override
|
||||
{
|
||||
LibNativeOrdersStorage.Storage storage stor =
|
||||
LibNativeOrdersStorage.getStorage();
|
||||
|
||||
uint256 oldMinValidSalt =
|
||||
stor.limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
|
||||
[msg.sender]
|
||||
[address(makerToken)]
|
||||
[address(takerToken)];
|
||||
|
||||
// New min salt must >= the old one.
|
||||
if (oldMinValidSalt > minValidSalt) {
|
||||
LibNativeOrdersRichErrors.
|
||||
CancelSaltTooLowError(minValidSalt, oldMinValidSalt)
|
||||
.rrevert();
|
||||
}
|
||||
|
||||
stor.limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
|
||||
[msg.sender]
|
||||
[address(makerToken)]
|
||||
[address(takerToken)] = minValidSalt;
|
||||
|
||||
emit PairOrdersCancelled(
|
||||
msg.sender,
|
||||
address(makerToken),
|
||||
address(takerToken),
|
||||
minValidSalt
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Cancel all limit orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerTokens The maker tokens.
|
||||
/// @param takerTokens The taker tokens.
|
||||
/// @param minValidSalts The new minimum valid salts.
|
||||
function batchCancelPairLimitOrders(
|
||||
IERC20TokenV06[] memory makerTokens,
|
||||
IERC20TokenV06[] memory takerTokens,
|
||||
uint256[] memory minValidSalts
|
||||
)
|
||||
public
|
||||
override
|
||||
{
|
||||
require(
|
||||
makerTokens.length == takerTokens.length &&
|
||||
makerTokens.length == minValidSalts.length,
|
||||
"LimitOrdersFeature/MISMATCHED_PAIR_ORDERS_ARRAY_LENGTHS"
|
||||
);
|
||||
|
||||
for (uint256 i = 0; i < makerTokens.length; ++i) {
|
||||
cancelPairLimitOrders(
|
||||
makerTokens[i],
|
||||
takerTokens[i],
|
||||
minValidSalts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerToken The maker token.
|
||||
/// @param takerToken The taker token.
|
||||
/// @param minValidSalt The new minimum valid salt.
|
||||
function cancelPairRfqOrders(
|
||||
IERC20TokenV06 makerToken,
|
||||
IERC20TokenV06 takerToken,
|
||||
uint256 minValidSalt
|
||||
)
|
||||
public
|
||||
override
|
||||
{
|
||||
LibNativeOrdersStorage.Storage storage stor =
|
||||
LibNativeOrdersStorage.getStorage();
|
||||
|
||||
uint256 oldMinValidSalt =
|
||||
stor.rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
|
||||
[msg.sender]
|
||||
[address(makerToken)]
|
||||
[address(takerToken)];
|
||||
|
||||
// New min salt must >= the old one.
|
||||
if (oldMinValidSalt > minValidSalt) {
|
||||
LibNativeOrdersRichErrors.
|
||||
CancelSaltTooLowError(minValidSalt, oldMinValidSalt)
|
||||
.rrevert();
|
||||
}
|
||||
|
||||
stor.rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
|
||||
[msg.sender]
|
||||
[address(makerToken)]
|
||||
[address(takerToken)] = minValidSalt;
|
||||
|
||||
emit PairOrdersCancelled(
|
||||
msg.sender,
|
||||
address(makerToken),
|
||||
address(takerToken),
|
||||
minValidSalt
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
|
||||
/// than the value provided. The caller must be the maker. Subsequent
|
||||
/// calls to this function with the same caller and pair require the
|
||||
/// new salt to be >= the old salt.
|
||||
/// @param makerTokens The maker tokens.
|
||||
/// @param takerTokens The taker tokens.
|
||||
/// @param minValidSalts The new minimum valid salts.
|
||||
function batchCancelPairRfqOrders(
|
||||
IERC20TokenV06[] memory makerTokens,
|
||||
IERC20TokenV06[] memory takerTokens,
|
||||
uint256[] memory minValidSalts
|
||||
)
|
||||
public
|
||||
override
|
||||
{
|
||||
require(
|
||||
makerTokens.length == takerTokens.length &&
|
||||
makerTokens.length == minValidSalts.length,
|
||||
"LimitOrdersFeature/MISMATCHED_PAIR_ORDERS_ARRAY_LENGTHS"
|
||||
);
|
||||
|
||||
for (uint256 i = 0; i < makerTokens.length; ++i) {
|
||||
cancelPairRfqOrders(
|
||||
makerTokens[i],
|
||||
takerTokens[i],
|
||||
minValidSalts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Get the order info for a limit order.
|
||||
/// @param order The limit order.
|
||||
/// @return orderInfo Info about the order.
|
||||
function getLimitOrderInfo(LibNativeOrder.LimitOrder memory order)
|
||||
public
|
||||
override
|
||||
view
|
||||
returns (LibNativeOrder.OrderInfo memory orderInfo)
|
||||
{
|
||||
// Recover maker and compute order hash.
|
||||
orderInfo.orderHash = getLimitOrderHash(order);
|
||||
uint256 minValidSalt = LibNativeOrdersStorage.getStorage()
|
||||
.limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
|
||||
[order.maker]
|
||||
[address(order.makerToken)]
|
||||
[address(order.takerToken)];
|
||||
_populateCommonOrderInfoFields(
|
||||
orderInfo,
|
||||
order.takerAmount,
|
||||
order.expiry,
|
||||
order.salt,
|
||||
minValidSalt
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Get the order info for an RFQ order.
|
||||
/// @param order The RFQ order.
|
||||
/// @return orderInfo Info about the order.
|
||||
function getRfqOrderInfo(LibNativeOrder.RfqOrder memory order)
|
||||
public
|
||||
override
|
||||
view
|
||||
returns (LibNativeOrder.OrderInfo memory orderInfo)
|
||||
{
|
||||
// Recover maker and compute order hash.
|
||||
orderInfo.orderHash = getRfqOrderHash(order);
|
||||
uint256 minValidSalt = LibNativeOrdersStorage.getStorage()
|
||||
.rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
|
||||
[order.maker]
|
||||
[address(order.makerToken)]
|
||||
[address(order.takerToken)];
|
||||
_populateCommonOrderInfoFields(
|
||||
orderInfo,
|
||||
order.takerAmount,
|
||||
order.expiry,
|
||||
order.salt,
|
||||
minValidSalt
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Get the canonical hash of a limit order.
|
||||
/// @param order The limit order.
|
||||
/// @return orderHash The order hash.
|
||||
function getLimitOrderHash(LibNativeOrder.LimitOrder memory order)
|
||||
public
|
||||
override
|
||||
view
|
||||
returns (bytes32 orderHash)
|
||||
{
|
||||
return _getEIP712Hash(
|
||||
LibNativeOrder.getLimitOrderStructHash(order)
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Get the canonical hash of an RFQ order.
|
||||
/// @param order The RFQ order.
|
||||
/// @return orderHash The order hash.
|
||||
function getRfqOrderHash(LibNativeOrder.RfqOrder memory order)
|
||||
public
|
||||
override
|
||||
view
|
||||
returns (bytes32 orderHash)
|
||||
{
|
||||
return _getEIP712Hash(
|
||||
LibNativeOrder.getRfqOrderStructHash(order)
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Get the protocol fee multiplier. This should be multiplied by the
|
||||
/// gas price to arrive at the required protocol fee to fill a native order.
|
||||
/// @return multiplier The protocol fee multiplier.
|
||||
function getProtocolFeeMultiplier()
|
||||
external
|
||||
override
|
||||
view
|
||||
returns (uint32 multiplier)
|
||||
{
|
||||
return PROTOCOL_FEE_MULTIPLIER;
|
||||
}
|
||||
|
||||
/// @dev Populate `status` and `takerTokenFilledAmount` fields in
|
||||
/// `orderInfo`, which use the same code path for both limit and
|
||||
/// RFQ orders.
|
||||
/// @param orderInfo `OrderInfo` with `orderHash` and `maker` filled.
|
||||
/// @param takerAmount The order's taker token amount..
|
||||
/// @param expiry The order's expiry.
|
||||
/// @param salt The order's salt.
|
||||
/// @param salt The minimum valid salt for the maker and pair combination.
|
||||
function _populateCommonOrderInfoFields(
|
||||
LibNativeOrder.OrderInfo memory orderInfo,
|
||||
uint128 takerAmount,
|
||||
uint64 expiry,
|
||||
uint256 salt,
|
||||
uint256 minValidSalt
|
||||
)
|
||||
private
|
||||
view
|
||||
{
|
||||
LibNativeOrdersStorage.Storage storage stor =
|
||||
LibNativeOrdersStorage.getStorage();
|
||||
|
||||
// Get the filled and direct cancel state.
|
||||
{
|
||||
// The high bit of the raw taker token filled amount will be set
|
||||
// if the order was cancelled.
|
||||
uint256 rawTakerTokenFilledAmount =
|
||||
stor.orderHashToTakerTokenFilledAmount[orderInfo.orderHash];
|
||||
orderInfo.takerTokenFilledAmount = uint128(rawTakerTokenFilledAmount);
|
||||
if (orderInfo.takerTokenFilledAmount >= takerAmount) {
|
||||
orderInfo.status = LibNativeOrder.OrderStatus.FILLED;
|
||||
return;
|
||||
}
|
||||
if (rawTakerTokenFilledAmount & HIGH_BIT != 0) {
|
||||
orderInfo.status = LibNativeOrder.OrderStatus.CANCELLED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for expiration.
|
||||
if (expiry <= uint64(block.timestamp)) {
|
||||
orderInfo.status = LibNativeOrder.OrderStatus.EXPIRED;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the order was cancelled by salt.
|
||||
if (minValidSalt > salt) {
|
||||
orderInfo.status = LibNativeOrder.OrderStatus.CANCELLED;
|
||||
return;
|
||||
}
|
||||
orderInfo.status = LibNativeOrder.OrderStatus.FILLABLE;
|
||||
}
|
||||
|
||||
/// @dev Cancel a limit or RFQ order directly by its order hash.
|
||||
/// @param orderHash The order's order hash.
|
||||
/// @param maker The order's maker.
|
||||
function _cancelOrderHash(bytes32 orderHash, address maker)
|
||||
private
|
||||
{
|
||||
LibNativeOrdersStorage.Storage storage stor =
|
||||
LibNativeOrdersStorage.getStorage();
|
||||
// Set the high bit on the raw taker token fill amount to indicate
|
||||
// a cancel. It's OK to cancel twice.
|
||||
stor.orderHashToTakerTokenFilledAmount[orderHash] |= HIGH_BIT;
|
||||
|
||||
emit OrderCancelled(orderHash, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Fill a limit order. Private variant. Does not refund protocol fees.
|
||||
/// @param params Function params.
|
||||
/// @return results Results of the fill.
|
||||
function _fillLimitOrderPrivate(FillLimitOrderPrivateParams memory params)
|
||||
private
|
||||
returns (FillNativeOrderResults memory results)
|
||||
{
|
||||
LibNativeOrder.OrderInfo memory orderInfo = getLimitOrderInfo(params.order);
|
||||
|
||||
// Must be fillable.
|
||||
if (orderInfo.status != LibNativeOrder.OrderStatus.FILLABLE) {
|
||||
LibNativeOrdersRichErrors.OrderNotFillableError(
|
||||
orderInfo.orderHash,
|
||||
uint8(orderInfo.status)
|
||||
).rrevert();
|
||||
}
|
||||
|
||||
// Must be fillable by the taker.
|
||||
if (params.order.taker != address(0) && params.order.taker != params.taker) {
|
||||
LibNativeOrdersRichErrors.OrderNotFillableByTakerError(
|
||||
orderInfo.orderHash,
|
||||
params.taker,
|
||||
params.order.taker
|
||||
).rrevert();
|
||||
}
|
||||
|
||||
// Must be fillable by the sender.
|
||||
if (params.order.sender != address(0) && params.order.sender != params.sender) {
|
||||
LibNativeOrdersRichErrors.OrderNotFillableBySenderError(
|
||||
orderInfo.orderHash,
|
||||
params.sender,
|
||||
params.order.sender
|
||||
).rrevert();
|
||||
}
|
||||
|
||||
// Signature must be valid for the order.
|
||||
{
|
||||
address signer = LibSignature.getSignerOfHash(
|
||||
orderInfo.orderHash,
|
||||
params.signature
|
||||
);
|
||||
if (signer != params.order.maker) {
|
||||
LibNativeOrdersRichErrors.OrderNotSignedByMakerError(
|
||||
orderInfo.orderHash,
|
||||
signer,
|
||||
params.order.maker
|
||||
).rrevert();
|
||||
}
|
||||
}
|
||||
|
||||
// Pay the protocol fee.
|
||||
results.ethProtocolFeePaid = _collectProtocolFee(params.order.pool);
|
||||
|
||||
// Settle between the maker and taker.
|
||||
(results.takerTokenFilledAmount, results.makerTokenFilledAmount) = _settleOrder(
|
||||
SettleOrderInfo({
|
||||
orderHash: orderInfo.orderHash,
|
||||
maker: params.order.maker,
|
||||
taker: params.taker,
|
||||
makerToken: IERC20TokenV06(params.order.makerToken),
|
||||
takerToken: IERC20TokenV06(params.order.takerToken),
|
||||
makerAmount: params.order.makerAmount,
|
||||
takerAmount: params.order.takerAmount,
|
||||
takerTokenFillAmount: params.takerTokenFillAmount,
|
||||
takerTokenFilledAmount: orderInfo.takerTokenFilledAmount
|
||||
})
|
||||
);
|
||||
|
||||
// Pay the fee recipient.
|
||||
if (params.order.takerTokenFeeAmount > 0) {
|
||||
results.takerTokenFeeFilledAmount = uint128(LibMathV06.getPartialAmountFloor(
|
||||
results.takerTokenFilledAmount,
|
||||
params.order.takerAmount,
|
||||
params.order.takerTokenFeeAmount
|
||||
));
|
||||
LibTokenSpender.spendERC20Tokens(
|
||||
params.order.takerToken,
|
||||
params.taker,
|
||||
params.order.feeRecipient,
|
||||
uint256(results.takerTokenFeeFilledAmount),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
emit LimitOrderFilled(
|
||||
orderInfo.orderHash,
|
||||
params.order.maker,
|
||||
params.taker,
|
||||
params.order.feeRecipient,
|
||||
address(params.order.makerToken),
|
||||
address(params.order.takerToken),
|
||||
results.takerTokenFilledAmount,
|
||||
results.makerTokenFilledAmount,
|
||||
results.takerTokenFeeFilledAmount,
|
||||
results.ethProtocolFeePaid,
|
||||
params.order.pool
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Fill an RFQ order. Private variant. Does not refund protocol fees.
|
||||
/// @param order The RFQ order.
|
||||
/// @param signature The order signature.
|
||||
/// @param takerTokenFillAmount Maximum taker token to fill this order with.
|
||||
/// @param taker The order taker.
|
||||
/// @return results Results of the fill.
|
||||
function _fillRfqOrderPrivate(
|
||||
LibNativeOrder.RfqOrder memory order,
|
||||
LibSignature.Signature memory signature,
|
||||
uint128 takerTokenFillAmount,
|
||||
address taker
|
||||
)
|
||||
private
|
||||
returns (FillNativeOrderResults memory results)
|
||||
{
|
||||
LibNativeOrder.OrderInfo memory orderInfo = getRfqOrderInfo(order);
|
||||
|
||||
// Must be fillable.
|
||||
if (orderInfo.status != LibNativeOrder.OrderStatus.FILLABLE) {
|
||||
LibNativeOrdersRichErrors.OrderNotFillableError(
|
||||
orderInfo.orderHash,
|
||||
uint8(orderInfo.status)
|
||||
).rrevert();
|
||||
}
|
||||
|
||||
// Must be fillable by the tx.origin.
|
||||
if (order.txOrigin != address(0) && order.txOrigin != tx.origin) {
|
||||
LibNativeOrdersRichErrors.OrderNotFillableByOriginError(
|
||||
orderInfo.orderHash,
|
||||
tx.origin,
|
||||
order.txOrigin
|
||||
).rrevert();
|
||||
}
|
||||
|
||||
// Signature must be valid for the order.
|
||||
{
|
||||
address signer = LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
|
||||
if (signer != order.maker) {
|
||||
LibNativeOrdersRichErrors.OrderNotSignedByMakerError(
|
||||
orderInfo.orderHash,
|
||||
signer,
|
||||
order.maker
|
||||
).rrevert();
|
||||
}
|
||||
}
|
||||
|
||||
// Pay the protocol fee.
|
||||
results.ethProtocolFeePaid = _collectProtocolFee(order.pool);
|
||||
|
||||
// Settle between the maker and taker.
|
||||
(results.takerTokenFilledAmount, results.makerTokenFilledAmount) = _settleOrder(
|
||||
SettleOrderInfo({
|
||||
orderHash: orderInfo.orderHash,
|
||||
maker: order.maker,
|
||||
taker: taker,
|
||||
makerToken: IERC20TokenV06(order.makerToken),
|
||||
takerToken: IERC20TokenV06(order.takerToken),
|
||||
makerAmount: order.makerAmount,
|
||||
takerAmount: order.takerAmount,
|
||||
takerTokenFillAmount: takerTokenFillAmount,
|
||||
takerTokenFilledAmount: orderInfo.takerTokenFilledAmount
|
||||
})
|
||||
);
|
||||
|
||||
emit RfqOrderFilled(
|
||||
orderInfo.orderHash,
|
||||
order.maker,
|
||||
taker,
|
||||
address(order.makerToken),
|
||||
address(order.takerToken),
|
||||
results.takerTokenFilledAmount,
|
||||
results.makerTokenFilledAmount,
|
||||
results.ethProtocolFeePaid,
|
||||
order.pool
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Settle the trade between an order's maker and taker.
|
||||
/// @param settleInfo Information needed to execute the settlement.
|
||||
/// @return takerTokenFilledAmount How much taker token was filled.
|
||||
/// @return makerTokenFilledAmount How much maker token was filled.
|
||||
function _settleOrder(SettleOrderInfo memory settleInfo)
|
||||
private
|
||||
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
|
||||
{
|
||||
// Clamp the taker token fill amount to the fillable amount.
|
||||
takerTokenFilledAmount = LibSafeMathV06.min128(
|
||||
settleInfo.takerTokenFillAmount,
|
||||
settleInfo.takerAmount.safeSub128(settleInfo.takerTokenFilledAmount)
|
||||
);
|
||||
// Compute the maker token amount.
|
||||
// This should never overflow because the values are all clamped to
|
||||
// (2^128-1).
|
||||
makerTokenFilledAmount = uint128(LibMathV06.getPartialAmountFloor(
|
||||
uint256(takerTokenFilledAmount),
|
||||
uint256(settleInfo.takerAmount),
|
||||
uint256(settleInfo.makerAmount)
|
||||
));
|
||||
|
||||
if (takerTokenFilledAmount == 0 || makerTokenFilledAmount == 0) {
|
||||
// Nothing to do.
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
// Update filled state for the order.
|
||||
LibNativeOrdersStorage
|
||||
.getStorage()
|
||||
.orderHashToTakerTokenFilledAmount[settleInfo.orderHash] =
|
||||
// OK to overwrite the whole word because we shouldn't get to this
|
||||
// function if the order is cancelled.
|
||||
settleInfo.takerTokenFilledAmount.safeAdd128(takerTokenFilledAmount);
|
||||
|
||||
// Transfer taker -> maker.
|
||||
LibTokenSpender.spendERC20Tokens(
|
||||
settleInfo.takerToken,
|
||||
settleInfo.taker,
|
||||
settleInfo.maker,
|
||||
takerTokenFilledAmount,
|
||||
false
|
||||
);
|
||||
|
||||
// Transfer maker -> taker.
|
||||
LibTokenSpender.spendERC20Tokens(
|
||||
settleInfo.makerToken,
|
||||
settleInfo.maker,
|
||||
settleInfo.taker,
|
||||
makerTokenFilledAmount,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Refund any leftover protocol fees in `msg.value` to `msg.sender`.
|
||||
/// @param ethProtocolFeePaid How much ETH was paid in protocol fees.
|
||||
function _refundExcessProtocolFeeToSender(uint256 ethProtocolFeePaid)
|
||||
private
|
||||
{
|
||||
if (msg.value > ethProtocolFeePaid && msg.sender != address(this)) {
|
||||
uint256 refundAmount = msg.value.safeSub(ethProtocolFeePaid);
|
||||
(bool success,) = msg
|
||||
.sender
|
||||
.call{value: refundAmount}("");
|
||||
if (!success) {
|
||||
LibNativeOrdersRichErrors.ProtocolFeeRefundFailed(
|
||||
msg.sender,
|
||||
refundAmount
|
||||
).rrevert();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -56,6 +56,7 @@ contract SimpleFunctionRegistryFeature is
|
||||
// Register getters.
|
||||
_extend(this.getRollbackLength.selector, _implementation);
|
||||
_extend(this.getRollbackEntryAtIndex.selector, _implementation);
|
||||
_extend(this.getFunctionImplementation.selector, _implementation);
|
||||
return LibBootstrap.BOOTSTRAP_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -151,6 +152,18 @@ contract SimpleFunctionRegistryFeature is
|
||||
return LibSimpleFunctionRegistryStorage.getStorage().implHistory[selector][idx];
|
||||
}
|
||||
|
||||
/// @dev Get the implementation contract of a registered function.
|
||||
/// @param selector The function selector.
|
||||
/// @return impl The implementation contract address.
|
||||
function getFunctionImplementation(bytes4 selector)
|
||||
external
|
||||
override
|
||||
view
|
||||
returns (address impl)
|
||||
{
|
||||
return LibProxyStorage.getStorage().impls[selector];
|
||||
}
|
||||
|
||||
/// @dev Register or replace a function.
|
||||
/// @param selector The function selector.
|
||||
/// @param impl The implementation contract for the function.
|
||||
|
@@ -58,7 +58,7 @@ contract TransformERC20Feature is
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "TransformERC20";
|
||||
/// @dev Version of this feature.
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 0);
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 3, 1);
|
||||
|
||||
/// @dev Initialize and register this feature.
|
||||
/// Should be delegatecalled by `Migrate.migrate()`.
|
||||
@@ -317,7 +317,13 @@ contract TransformERC20Feature is
|
||||
// Transfer input tokens.
|
||||
if (!LibERC20Transformer.isTokenETH(inputToken)) {
|
||||
// Token is not ETH, so pull ERC20 tokens.
|
||||
LibTokenSpender.spendERC20Tokens(inputToken, from, to, amount);
|
||||
LibTokenSpender.spendERC20Tokens(
|
||||
inputToken,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
true
|
||||
);
|
||||
} else if (msg.value < amount) {
|
||||
// Token is ETH, so the caller must attach enough ETH to the call.
|
||||
LibTransformERC20RichErrors.InsufficientEthAttachedError(
|
||||
|
@@ -37,7 +37,7 @@ contract UniswapFeature is
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "UniswapFeature";
|
||||
/// @dev Version of this feature.
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
|
||||
/// @dev WETH contract.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
/// @dev AllowanceTarget instance.
|
||||
|
213
contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol
Normal file
213
contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
|
||||
|
||||
/// @dev A library for common native order operations.
|
||||
library LibNativeOrder {
|
||||
|
||||
enum OrderStatus {
|
||||
INVALID,
|
||||
FILLABLE,
|
||||
FILLED,
|
||||
CANCELLED,
|
||||
EXPIRED
|
||||
}
|
||||
|
||||
/// @dev A standard OTC or OO limit order.
|
||||
struct LimitOrder {
|
||||
IERC20TokenV06 makerToken;
|
||||
IERC20TokenV06 takerToken;
|
||||
uint128 makerAmount;
|
||||
uint128 takerAmount;
|
||||
uint128 takerTokenFeeAmount;
|
||||
address maker;
|
||||
address taker;
|
||||
address sender;
|
||||
address feeRecipient;
|
||||
bytes32 pool;
|
||||
uint64 expiry;
|
||||
uint256 salt;
|
||||
}
|
||||
|
||||
/// @dev An RFQ limit order.
|
||||
struct RfqOrder {
|
||||
IERC20TokenV06 makerToken;
|
||||
IERC20TokenV06 takerToken;
|
||||
uint128 makerAmount;
|
||||
uint128 takerAmount;
|
||||
address maker;
|
||||
address txOrigin;
|
||||
bytes32 pool;
|
||||
uint64 expiry;
|
||||
uint256 salt;
|
||||
}
|
||||
|
||||
/// @dev Info on a limit or RFQ order.
|
||||
struct OrderInfo {
|
||||
bytes32 orderHash;
|
||||
OrderStatus status;
|
||||
uint128 takerTokenFilledAmount;
|
||||
}
|
||||
|
||||
uint256 private constant UINT_128_MASK = (1 << 128) - 1;
|
||||
uint256 private constant UINT_64_MASK = (1 << 64) - 1;
|
||||
uint256 private constant ADDRESS_MASK = (1 << 160) - 1;
|
||||
|
||||
// The type hash for limit orders, which is:
|
||||
// keccak256(abi.encodePacked(
|
||||
// "LimitOrder(",
|
||||
// "address makerToken,",
|
||||
// "address takerToken,",
|
||||
// "uint128 makerAmount,",
|
||||
// "uint128 takerAmount,",
|
||||
// "uint128 takerTokenFeeAmount,",
|
||||
// "address maker,",
|
||||
// "address taker,",
|
||||
// "address sender,",
|
||||
// "address feeRecipient,",
|
||||
// "bytes32 pool,",
|
||||
// "uint64 expiry,",
|
||||
// "uint256 salt"
|
||||
// ")"
|
||||
// ))
|
||||
uint256 private constant _LIMIT_ORDER_TYPEHASH =
|
||||
0xce918627cb55462ddbb85e73de69a8b322f2bc88f4507c52fcad6d4c33c29d49;
|
||||
|
||||
// The type hash for RFQ orders, which is:
|
||||
// keccak256(abi.encodePacked(
|
||||
// "RfqOrder(",
|
||||
// "address makerToken,",
|
||||
// "address takerToken,",
|
||||
// "uint128 makerAmount,",
|
||||
// "uint128 takerAmount,",
|
||||
// "address maker,",
|
||||
// "address txOrigin,",
|
||||
// "bytes32 pool,",
|
||||
// "uint64 expiry,",
|
||||
// "uint256 salt"
|
||||
// ")"
|
||||
// ))
|
||||
uint256 private constant _RFQ_ORDER_TYPEHASH =
|
||||
0xc6b3034376598bc7f28b05e81db7ed88486dcdb6b4a6c7300353fffc5f31f382;
|
||||
|
||||
/// @dev Get the struct hash of a limit order.
|
||||
/// @param order The limit order.
|
||||
/// @return structHash The struct hash of the order.
|
||||
function getLimitOrderStructHash(LimitOrder memory order)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32 structHash)
|
||||
{
|
||||
// The struct hash is:
|
||||
// keccak256(abi.encode(
|
||||
// TYPE_HASH,
|
||||
// order.makerToken,
|
||||
// order.takerToken,
|
||||
// order.makerAmount,
|
||||
// order.takerAmount,
|
||||
// order.takerTokenFeeAmount,
|
||||
// order.maker,
|
||||
// order.taker,
|
||||
// order.sender,
|
||||
// order.feeRecipient,
|
||||
// order.pool,
|
||||
// order.expiry,
|
||||
// order.salt,
|
||||
// ))
|
||||
assembly {
|
||||
let mem := mload(0x40)
|
||||
mstore(mem, _LIMIT_ORDER_TYPEHASH)
|
||||
// order.makerToken;
|
||||
mstore(add(mem, 0x20), and(ADDRESS_MASK, mload(order)))
|
||||
// order.takerToken;
|
||||
mstore(add(mem, 0x40), and(ADDRESS_MASK, mload(add(order, 0x20))))
|
||||
// order.makerAmount;
|
||||
mstore(add(mem, 0x60), and(UINT_128_MASK, mload(add(order, 0x40))))
|
||||
// order.takerAmount;
|
||||
mstore(add(mem, 0x80), and(UINT_128_MASK, mload(add(order, 0x60))))
|
||||
// order.takerTokenFeeAmount;
|
||||
mstore(add(mem, 0xA0), and(UINT_128_MASK, mload(add(order, 0x80))))
|
||||
// order.maker;
|
||||
mstore(add(mem, 0xC0), and(ADDRESS_MASK, mload(add(order, 0xA0))))
|
||||
// order.taker;
|
||||
mstore(add(mem, 0xE0), and(ADDRESS_MASK, mload(add(order, 0xC0))))
|
||||
// order.sender;
|
||||
mstore(add(mem, 0x100), and(ADDRESS_MASK, mload(add(order, 0xE0))))
|
||||
// order.feeRecipient;
|
||||
mstore(add(mem, 0x120), and(ADDRESS_MASK, mload(add(order, 0x100))))
|
||||
// order.pool;
|
||||
mstore(add(mem, 0x140), mload(add(order, 0x120)))
|
||||
// order.expiry;
|
||||
mstore(add(mem, 0x160), and(UINT_64_MASK, mload(add(order, 0x140))))
|
||||
// order.salt;
|
||||
mstore(add(mem, 0x180), mload(add(order, 0x160)))
|
||||
structHash := keccak256(mem, 0x1A0)
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Get the struct hash of a RFQ order.
|
||||
/// @param order The RFQ order.
|
||||
/// @return structHash The struct hash of the order.
|
||||
function getRfqOrderStructHash(RfqOrder memory order)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32 structHash)
|
||||
{
|
||||
// The struct hash is:
|
||||
// keccak256(abi.encode(
|
||||
// TYPE_HASH,
|
||||
// order.makerToken,
|
||||
// order.takerToken,
|
||||
// order.makerAmount,
|
||||
// order.takerAmount,
|
||||
// order.maker,
|
||||
// order.txOrigin,
|
||||
// order.pool,
|
||||
// order.expiry,
|
||||
// order.salt,
|
||||
// ))
|
||||
assembly {
|
||||
let mem := mload(0x40)
|
||||
mstore(mem, _RFQ_ORDER_TYPEHASH)
|
||||
// order.makerToken;
|
||||
mstore(add(mem, 0x20), and(ADDRESS_MASK, mload(order)))
|
||||
// order.takerToken;
|
||||
mstore(add(mem, 0x40), and(ADDRESS_MASK, mload(add(order, 0x20))))
|
||||
// order.makerAmount;
|
||||
mstore(add(mem, 0x60), and(UINT_128_MASK, mload(add(order, 0x40))))
|
||||
// order.takerAmount;
|
||||
mstore(add(mem, 0x80), and(UINT_128_MASK, mload(add(order, 0x60))))
|
||||
// order.maker;
|
||||
mstore(add(mem, 0xA0), and(ADDRESS_MASK, mload(add(order, 0x80))))
|
||||
// order.txOrigin;
|
||||
mstore(add(mem, 0xC0), and(ADDRESS_MASK, mload(add(order, 0xA0))))
|
||||
// order.pool;
|
||||
mstore(add(mem, 0xE0), mload(add(order, 0xC0)))
|
||||
// order.expiry;
|
||||
mstore(add(mem, 0x100), and(UINT_64_MASK, mload(add(order, 0xE0))))
|
||||
// order.salt;
|
||||
mstore(add(mem, 0x120), mload(add(order, 0x100)))
|
||||
structHash := keccak256(mem, 0x140)
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,11 +35,14 @@ library LibTokenSpender {
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @param to The recipient of the tokens.
|
||||
/// @param amount The amount of `token` to transfer.
|
||||
/// @param checkAllowance Whether or not to check the owner's allowance
|
||||
/// prior to attempting the transfer.
|
||||
function spendERC20Tokens(
|
||||
IERC20TokenV06 token,
|
||||
address owner,
|
||||
address to,
|
||||
uint256 amount
|
||||
uint256 amount,
|
||||
bool checkAllowance
|
||||
)
|
||||
internal
|
||||
{
|
||||
@@ -48,6 +51,19 @@ library LibTokenSpender {
|
||||
|
||||
require(address(token) != address(this), "LibTokenSpender/CANNOT_INVOKE_SELF");
|
||||
|
||||
if (checkAllowance) {
|
||||
// If the owner doesn't have a sufficient allowance set on `address(this)`,
|
||||
// try the old AllowanceTarget.
|
||||
if (token.allowance(owner, address(this)) < amount) {
|
||||
return ITokenSpenderFeature(address(this))._spendERC20Tokens(
|
||||
token,
|
||||
owner,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
assembly {
|
||||
let ptr := mload(0x40) // free memory pointer
|
||||
|
||||
|
@@ -22,48 +22,55 @@ pragma experimental ABIEncoderV2;
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "../external/FeeCollector.sol";
|
||||
import "../features/libs/LibTokenSpender.sol";
|
||||
import "../vendor/v3/IStaking.sol";
|
||||
|
||||
|
||||
/// @dev Helpers for collecting protocol fees.
|
||||
abstract contract FixinProtocolFees {
|
||||
bytes32 immutable feeCollectorCodeHash;
|
||||
/// @dev The protocol fee multiplier.
|
||||
uint32 public immutable PROTOCOL_FEE_MULTIPLIER;
|
||||
/// @dev Hash of the fee collector init code.
|
||||
bytes32 private immutable FEE_COLLECTOR_INIT_CODE_HASH;
|
||||
/// @dev The WETH token contract.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
/// @dev The staking contract.
|
||||
IStaking private immutable STAKING;
|
||||
|
||||
constructor() internal {
|
||||
feeCollectorCodeHash = keccak256(type(FeeCollector).creationCode);
|
||||
}
|
||||
|
||||
/// @dev Collect the specified protocol fee in either WETH or ETH. If
|
||||
/// msg.value is non-zero, the fee will be paid in ETH. Otherwise,
|
||||
/// this function attempts to transfer the fee in WETH. Either way,
|
||||
/// The fee is stored in a per-pool fee collector contract.
|
||||
/// @param poolId The pool ID for which a fee is being collected.
|
||||
/// @param amount The amount of ETH/WETH to be collected.
|
||||
/// @param weth The WETH token contract.
|
||||
function _collectProtocolFee(
|
||||
bytes32 poolId,
|
||||
uint256 amount,
|
||||
IERC20TokenV06 weth
|
||||
constructor(
|
||||
IEtherTokenV06 weth,
|
||||
IStaking staking,
|
||||
uint32 protocolFeeMultiplier
|
||||
)
|
||||
internal
|
||||
{
|
||||
FeeCollector feeCollector = _getFeeCollector(poolId);
|
||||
FEE_COLLECTOR_INIT_CODE_HASH = keccak256(type(FeeCollector).creationCode);
|
||||
WETH = weth;
|
||||
STAKING = staking;
|
||||
PROTOCOL_FEE_MULTIPLIER = protocolFeeMultiplier;
|
||||
}
|
||||
|
||||
if (msg.value == 0) {
|
||||
// WETH
|
||||
LibTokenSpender.spendERC20Tokens(weth, msg.sender, address(feeCollector), amount);
|
||||
} else {
|
||||
// ETH
|
||||
(bool success,) = address(feeCollector).call{value: amount}("");
|
||||
require(success, "FixinProtocolFees/ETHER_TRANSFER_FALIED");
|
||||
/// @dev Collect the specified protocol fee in ETH.
|
||||
/// The fee is stored in a per-pool fee collector contract.
|
||||
/// @param poolId The pool ID for which a fee is being collected.
|
||||
/// @return ethProtocolFeePaid How much protocol fee was collected in ETH.
|
||||
function _collectProtocolFee(bytes32 poolId)
|
||||
internal
|
||||
returns (uint256 ethProtocolFeePaid)
|
||||
{
|
||||
uint256 protocolFeePaid = _getSingleProtocolFee();
|
||||
if (protocolFeePaid == 0) {
|
||||
// Nothing to do.
|
||||
return 0;
|
||||
}
|
||||
FeeCollector feeCollector = _getFeeCollector(poolId);
|
||||
(bool success,) = address(feeCollector).call{value: protocolFeePaid}("");
|
||||
require(success, "FixinProtocolFees/ETHER_TRANSFER_FALIED");
|
||||
return protocolFeePaid;
|
||||
}
|
||||
|
||||
/// @dev Transfer fees for a given pool to the staking contract.
|
||||
/// @param poolId Identifies the pool whose fees are being paid.
|
||||
function _transferFeesForPool(
|
||||
bytes32 poolId,
|
||||
IStaking staking,
|
||||
IEtherTokenV06 weth
|
||||
)
|
||||
function _transferFeesForPool(bytes32 poolId)
|
||||
internal
|
||||
{
|
||||
FeeCollector feeCollector = _getFeeCollector(poolId);
|
||||
@@ -75,18 +82,18 @@ abstract contract FixinProtocolFees {
|
||||
|
||||
if (codeSize == 0) {
|
||||
// Create and initialize the contract if necessary.
|
||||
new FeeCollector{salt: poolId}();
|
||||
feeCollector.initialize(weth, staking, poolId);
|
||||
new FeeCollector{salt: bytes32(poolId)}();
|
||||
feeCollector.initialize(WETH, STAKING, poolId);
|
||||
}
|
||||
|
||||
if (address(feeCollector).balance > 1) {
|
||||
feeCollector.convertToWeth(weth);
|
||||
feeCollector.convertToWeth(WETH);
|
||||
}
|
||||
|
||||
uint256 bal = weth.balanceOf(address(feeCollector));
|
||||
uint256 bal = WETH.balanceOf(address(feeCollector));
|
||||
if (bal > 1) {
|
||||
// Leave 1 wei behind to avoid high SSTORE cost of zero-->non-zero.
|
||||
staking.payProtocolFee(
|
||||
STAKING.payProtocolFee(
|
||||
address(feeCollector),
|
||||
address(feeCollector),
|
||||
bal - 1);
|
||||
@@ -95,9 +102,7 @@ abstract contract FixinProtocolFees {
|
||||
|
||||
/// @dev Compute the CREATE2 address for a fee collector.
|
||||
/// @param poolId The fee collector's pool ID.
|
||||
function _getFeeCollector(
|
||||
bytes32 poolId
|
||||
)
|
||||
function _getFeeCollector(bytes32 poolId)
|
||||
internal
|
||||
view
|
||||
returns (FeeCollector)
|
||||
@@ -107,8 +112,18 @@ abstract contract FixinProtocolFees {
|
||||
byte(0xff),
|
||||
address(this),
|
||||
poolId, // pool ID is salt
|
||||
feeCollectorCodeHash
|
||||
FEE_COLLECTOR_INIT_CODE_HASH
|
||||
))));
|
||||
return FeeCollector(addr);
|
||||
}
|
||||
|
||||
/// @dev Get the cost of a single protocol fee.
|
||||
/// @return protocolFeeAmount The protocol fee amount, in ETH/WETH.
|
||||
function _getSingleProtocolFee()
|
||||
internal
|
||||
view
|
||||
returns (uint256 protocolFeeAmount)
|
||||
{
|
||||
return uint256(PROTOCOL_FEE_MULTIPLIER) * tx.gasprice;
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ import "../features/TokenSpenderFeature.sol";
|
||||
import "../features/TransformERC20Feature.sol";
|
||||
import "../features/SignatureValidatorFeature.sol";
|
||||
import "../features/MetaTransactionsFeature.sol";
|
||||
import "../features/NativeOrdersFeature.sol";
|
||||
import "../external/AllowanceTarget.sol";
|
||||
import "./InitialMigration.sol";
|
||||
|
||||
@@ -42,6 +43,7 @@ contract FullMigration {
|
||||
TransformERC20Feature transformERC20;
|
||||
SignatureValidatorFeature signatureValidator;
|
||||
MetaTransactionsFeature metaTransactions;
|
||||
NativeOrdersFeature nativeOrders;
|
||||
}
|
||||
|
||||
/// @dev Parameters needed to initialize features.
|
||||
@@ -84,7 +86,7 @@ contract FullMigration {
|
||||
/// @param features Features to add to the proxy.
|
||||
/// @return _zeroEx The configured ZeroEx contract. Same as the `zeroEx` parameter.
|
||||
/// @param migrateOpts Parameters needed to initialize features.
|
||||
function initializeZeroEx(
|
||||
function migrateZeroEx(
|
||||
address payable owner,
|
||||
ZeroEx zeroEx,
|
||||
Features memory features,
|
||||
@@ -195,5 +197,16 @@ contract FullMigration {
|
||||
address(this)
|
||||
);
|
||||
}
|
||||
// NativeOrdersFeature
|
||||
{
|
||||
// Register the feature.
|
||||
ownable.migrate(
|
||||
address(features.nativeOrders),
|
||||
abi.encodeWithSelector(
|
||||
NativeOrdersFeature.migrate.selector
|
||||
),
|
||||
address(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,20 +22,29 @@ pragma experimental ABIEncoderV2;
|
||||
import "./LibStorage.sol";
|
||||
|
||||
|
||||
/// @dev Storage helpers for `LiquidityProviderFeature`.
|
||||
library LibLiquidityProviderStorage {
|
||||
/// @dev Storage helpers for `NativeOrdersFeature`.
|
||||
library LibNativeOrdersStorage {
|
||||
|
||||
/// @dev Storage bucket for this feature.
|
||||
struct Storage {
|
||||
// Mapping of taker token -> maker token -> liquidity provider address
|
||||
// Note that addressBook[x][y] == addressBook[y][x] will always hold.
|
||||
mapping (address => mapping (address => address)) addressBook;
|
||||
// How much taker token has been filled in order.
|
||||
// The lower `uint128` is the taker token fill amount.
|
||||
// The high bit will be `1` if the order was directly cancelled.
|
||||
mapping(bytes32 => uint256) orderHashToTakerTokenFilledAmount;
|
||||
// The minimum valid order salt for a given maker and order pair (maker, taker)
|
||||
// for limit orders.
|
||||
mapping(address => mapping(address => mapping(address => uint256)))
|
||||
limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt;
|
||||
// The minimum valid order salt for a given maker and order pair (maker, taker)
|
||||
// for RFQ orders.
|
||||
mapping(address => mapping(address => mapping(address => uint256)))
|
||||
rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt;
|
||||
}
|
||||
|
||||
/// @dev Get the storage bucket for this contract.
|
||||
function getStorage() internal pure returns (Storage storage stor) {
|
||||
uint256 storageSlot = LibStorage.getStorageSlot(
|
||||
LibStorage.StorageId.LiquidityProvider
|
||||
LibStorage.StorageId.NativeOrders
|
||||
);
|
||||
// Dip into assembly to change the slot pointed to by the local
|
||||
// variable `stor`.
|
@@ -37,7 +37,7 @@ library LibStorage {
|
||||
TransformERC20,
|
||||
MetaTransactions,
|
||||
ReentrancyGuard,
|
||||
LiquidityProvider
|
||||
NativeOrders
|
||||
}
|
||||
|
||||
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced
|
||||
|
@@ -1,19 +1,15 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
@@ -41,14 +37,13 @@ contract TestBridge is
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
||||
/// @return success The magic bytes `0xdc1600f3` if successful.
|
||||
function bridgeTransferFrom(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
bytes calldata /* bridgeData */
|
||||
)
|
||||
external
|
||||
override
|
||||
|
@@ -32,28 +32,26 @@ contract TestFillQuoteTransformerBridge {
|
||||
uint256 amount;
|
||||
}
|
||||
|
||||
bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
|
||||
|
||||
function bridgeTransferFrom(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
function sellTokenForToken(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
FillBehavior memory behavior = abi.decode(bridgeData, (FillBehavior));
|
||||
TestMintableERC20Token(tokenAddress).mint(
|
||||
to,
|
||||
LibMathV06.getPartialAmountFloor(
|
||||
behavior.makerAssetMintRatio,
|
||||
1e18,
|
||||
behavior.amount
|
||||
)
|
||||
FillBehavior memory behavior = abi.decode(auxiliaryData, (FillBehavior));
|
||||
boughtAmount = LibMathV06.getPartialAmountFloor(
|
||||
behavior.makerAssetMintRatio,
|
||||
1e18,
|
||||
behavior.amount
|
||||
);
|
||||
TestMintableERC20Token(makerToken).mint(
|
||||
recipient,
|
||||
boughtAmount
|
||||
);
|
||||
return ERC20_BRIDGE_PROXY_ID;
|
||||
}
|
||||
|
||||
function encodeBehaviorData(FillBehavior calldata behavior)
|
||||
|
@@ -21,26 +21,31 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/fixins/FixinProtocolFees.sol";
|
||||
|
||||
contract TestProtocolFees is FixinProtocolFees {
|
||||
function collectProtocolFee(
|
||||
bytes32 poolId,
|
||||
uint256 amount,
|
||||
IERC20TokenV06 weth
|
||||
contract TestFixinProtocolFees is
|
||||
FixinProtocolFees
|
||||
{
|
||||
constructor(
|
||||
IEtherTokenV06 weth,
|
||||
IStaking staking,
|
||||
uint32 protocolFeeMultiplier
|
||||
)
|
||||
public
|
||||
FixinProtocolFees(weth, staking, protocolFeeMultiplier)
|
||||
{
|
||||
// solhint-disalbe no-empty-blocks
|
||||
}
|
||||
|
||||
function collectProtocolFee(bytes32 poolId)
|
||||
external
|
||||
payable
|
||||
{
|
||||
_collectProtocolFee(poolId, amount, weth);
|
||||
_collectProtocolFee(poolId);
|
||||
}
|
||||
|
||||
function transferFeesForPool(
|
||||
bytes32 poolId,
|
||||
IStaking staking,
|
||||
IEtherTokenV06 weth
|
||||
)
|
||||
function transferFeesForPool(bytes32 poolId)
|
||||
external
|
||||
{
|
||||
_transferFeesForPool(poolId, staking, weth);
|
||||
_transferFeesForPool(poolId);
|
||||
}
|
||||
|
||||
function getFeeCollector(
|
||||
@@ -52,4 +57,12 @@ contract TestProtocolFees is FixinProtocolFees {
|
||||
{
|
||||
return _getFeeCollector(poolId);
|
||||
}
|
||||
|
||||
function getSingleProtocolFee()
|
||||
external
|
||||
view
|
||||
returns (uint256 protocolFeeAmount)
|
||||
{
|
||||
return _getSingleProtocolFee();
|
||||
}
|
||||
}
|
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
|
||||
import "../src/ZeroEx.sol";
|
||||
import "../src/features/IBootstrapFeature.sol";
|
||||
import "../src/migrations/InitialMigration.sol";
|
||||
import "../src/features/SimpleFunctionRegistryFeature.sol";
|
||||
|
||||
|
||||
contract TestInitialMigration is
|
||||
@@ -44,7 +45,8 @@ contract TestInitialMigration is
|
||||
{
|
||||
success = InitialMigration.bootstrap(owner, features);
|
||||
// Snoop the bootstrap feature contract.
|
||||
bootstrapFeature = ZeroEx(address(uint160(address(this))))
|
||||
bootstrapFeature =
|
||||
SimpleFunctionRegistryFeature(address(uint160(address(this))))
|
||||
.getFunctionImplementation(IBootstrapFeature.bootstrap.selector);
|
||||
}
|
||||
|
||||
|
24
contracts/zero-ex/contracts/test/TestLibNativeOrder.sol
Normal file
24
contracts/zero-ex/contracts/test/TestLibNativeOrder.sol
Normal file
@@ -0,0 +1,24 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/features/libs/LibNativeOrder.sol";
|
||||
|
||||
|
||||
contract TestLibNativeOrder {
|
||||
|
||||
function getLimitOrderStructHash(LibNativeOrder.LimitOrder calldata order)
|
||||
external
|
||||
pure
|
||||
returns (bytes32 structHash)
|
||||
{
|
||||
return LibNativeOrder.getLimitOrderStructHash(order);
|
||||
}
|
||||
|
||||
function getRfqOrderStructHash(LibNativeOrder.RfqOrder calldata order)
|
||||
external
|
||||
pure
|
||||
returns (bytes32 structHash)
|
||||
{
|
||||
return LibNativeOrder.getRfqOrderStructHash(order);
|
||||
}
|
||||
}
|
@@ -34,7 +34,13 @@ contract TestLibTokenSpender {
|
||||
)
|
||||
external
|
||||
{
|
||||
LibTokenSpender.spendERC20Tokens(token, owner, to, amount);
|
||||
LibTokenSpender.spendERC20Tokens(
|
||||
token,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
event FallbackCalled(
|
||||
|
135
contracts/zero-ex/contracts/test/TestLiquidityProvider.sol
Normal file
135
contracts/zero-ex/contracts/test/TestLiquidityProvider.sol
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
|
||||
|
||||
contract TestLiquidityProvider {
|
||||
event SellTokenForToken(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
uint256 inputTokenBalance
|
||||
);
|
||||
|
||||
event SellEthForToken(
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
uint256 ethBalance
|
||||
);
|
||||
|
||||
event SellTokenForEth(
|
||||
address inputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
uint256 inputTokenBalance
|
||||
);
|
||||
|
||||
IERC20TokenV06 public immutable xAsset;
|
||||
IERC20TokenV06 public immutable yAsset;
|
||||
|
||||
constructor(IERC20TokenV06 xAsset_, IERC20TokenV06 yAsset_)
|
||||
public
|
||||
{
|
||||
xAsset = xAsset_;
|
||||
yAsset = yAsset_;
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
|
||||
/// to sell must be transferred to the contract prior to calling this
|
||||
/// function to trigger the trade.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellTokenForToken(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
emit SellTokenForToken(
|
||||
inputToken,
|
||||
outputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
IERC20TokenV06(inputToken).balanceOf(address(this))
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Trades ETH for token. ETH must be sent to the contract prior to
|
||||
/// calling this function to trigger the trade.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of `outputToken` bought.
|
||||
function sellEthForToken(
|
||||
address outputToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
emit SellEthForToken(
|
||||
outputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
address(this).balance
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Trades token for ETH. The token must be sent to the contract prior
|
||||
/// to calling this function to trigger the trade.
|
||||
/// @param inputToken The token being sold.
|
||||
/// @param recipient The recipient of the bought tokens.
|
||||
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||
/// @return boughtAmount The amount of ETH bought.
|
||||
function sellTokenForEth(
|
||||
address inputToken,
|
||||
address payable recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
emit SellTokenForEth(
|
||||
inputToken,
|
||||
recipient,
|
||||
minBuyAmount,
|
||||
IERC20TokenV06(inputToken).balanceOf(address(this))
|
||||
);
|
||||
}
|
||||
}
|
24
contracts/zero-ex/contracts/test/TestNativeOrdersFeature.sol
Normal file
24
contracts/zero-ex/contracts/test/TestNativeOrdersFeature.sol
Normal file
@@ -0,0 +1,24 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/features/NativeOrdersFeature.sol";
|
||||
|
||||
contract TestNativeOrdersFeature is
|
||||
NativeOrdersFeature
|
||||
{
|
||||
constructor(
|
||||
address zeroExAddress,
|
||||
IEtherTokenV06 weth,
|
||||
IStaking staking,
|
||||
uint32 protocolFeeMultiplier
|
||||
)
|
||||
public
|
||||
NativeOrdersFeature(zeroExAddress, weth, staking, protocolFeeMultiplier)
|
||||
{
|
||||
// solhint-disable no-empty-blocks
|
||||
}
|
||||
|
||||
modifier onlySelf() override {
|
||||
_;
|
||||
}
|
||||
}
|
@@ -28,7 +28,7 @@ contract TestTransformerBase is
|
||||
IERC20Transformer,
|
||||
Transformer
|
||||
{
|
||||
function transform(TransformContext calldata context)
|
||||
function transform(TransformContext calldata /* context */)
|
||||
external
|
||||
override
|
||||
returns (bytes4 success)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-zero-ex",
|
||||
"version": "0.8.0",
|
||||
"version": "0.10.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -40,9 +40,9 @@
|
||||
"publish:private": "yarn build && gitpkg publish"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature",
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|IMetaTransactionsFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibLiquidityProviderStorage|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpender|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestLibSignature|TestLibTokenSpender|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestProtocolFees|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpender|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLibTokenSpender|TestLiquidityProvider|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -55,9 +55,9 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.4.7",
|
||||
"@0x/contracts-erc20": "^3.2.7",
|
||||
"@0x/contracts-erc20": "^3.2.9",
|
||||
"@0x/contracts-gen": "2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-test-utils": "^5.3.12",
|
||||
"@0x/dev-utils": "^4.0.1",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
@@ -76,7 +76,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.11",
|
||||
"@0x/order-utils": "^10.4.5",
|
||||
"@0x/order-utils": "^10.4.7",
|
||||
"@0x/subproviders": "^6.1.9",
|
||||
"@0x/types": "^3.3.0",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
|
@@ -12,6 +12,8 @@ import * as FullMigration from '../generated-artifacts/FullMigration.json';
|
||||
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
|
||||
import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.json';
|
||||
import * as IFlashWallet from '../generated-artifacts/IFlashWallet.json';
|
||||
import * as ILiquidityProviderFeature from '../generated-artifacts/ILiquidityProviderFeature.json';
|
||||
import * as INativeOrdersFeature from '../generated-artifacts/INativeOrdersFeature.json';
|
||||
import * as InitialMigration from '../generated-artifacts/InitialMigration.json';
|
||||
import * as IOwnableFeature from '../generated-artifacts/IOwnableFeature.json';
|
||||
import * as ISimpleFunctionRegistryFeature from '../generated-artifacts/ISimpleFunctionRegistryFeature.json';
|
||||
@@ -21,6 +23,7 @@ import * as IZeroEx from '../generated-artifacts/IZeroEx.json';
|
||||
import * as LiquidityProviderFeature from '../generated-artifacts/LiquidityProviderFeature.json';
|
||||
import * as LogMetadataTransformer from '../generated-artifacts/LogMetadataTransformer.json';
|
||||
import * as MetaTransactionsFeature from '../generated-artifacts/MetaTransactionsFeature.json';
|
||||
import * as NativeOrdersFeature from '../generated-artifacts/NativeOrdersFeature.json';
|
||||
import * as OwnableFeature from '../generated-artifacts/OwnableFeature.json';
|
||||
import * as PayTakerTransformer from '../generated-artifacts/PayTakerTransformer.json';
|
||||
import * as SignatureValidatorFeature from '../generated-artifacts/SignatureValidatorFeature.json';
|
||||
@@ -54,4 +57,7 @@ export const artifacts = {
|
||||
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
|
||||
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
||||
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
|
||||
ILiquidityProviderFeature: ILiquidityProviderFeature as ContractArtifact,
|
||||
NativeOrdersFeature: NativeOrdersFeature as ContractArtifact,
|
||||
INativeOrdersFeature: INativeOrdersFeature as ContractArtifact,
|
||||
};
|
||||
|
70
contracts/zero-ex/src/eip712_utils.ts
Normal file
70
contracts/zero-ex/src/eip712_utils.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { hexUtils, NULL_ADDRESS } from '@0x/utils';
|
||||
|
||||
export interface EIP712Domain {
|
||||
name: string;
|
||||
version: string;
|
||||
chainId: number;
|
||||
verifyingContract: string;
|
||||
}
|
||||
|
||||
export const EIP712_DOMAIN_PARAMETERS = [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'version', type: 'string' },
|
||||
{ name: 'chainId', type: 'uint256' },
|
||||
{ name: 'verifyingContract', type: 'address' },
|
||||
];
|
||||
|
||||
const EXCHANGE_PROXY_EIP712_DOMAIN_DEFAULT = {
|
||||
chainId: 1,
|
||||
verifyingContract: NULL_ADDRESS,
|
||||
name: 'ZeroEx',
|
||||
version: '1.0.0',
|
||||
};
|
||||
|
||||
const EXCHANGE_PROXY_DOMAIN_TYPEHASH = hexUtils.hash(
|
||||
hexUtils.toHex(
|
||||
Buffer.from(
|
||||
[
|
||||
'EIP712Domain(',
|
||||
['string name', 'string version', 'uint256 chainId', 'address verifyingContract'].join(','),
|
||||
')',
|
||||
].join(''),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Create an exchange proxy EIP712 domain.
|
||||
*/
|
||||
export function createExchangeProxyEIP712Domain(chainId?: number, verifyingContract?: string): EIP712Domain {
|
||||
return {
|
||||
...EXCHANGE_PROXY_EIP712_DOMAIN_DEFAULT,
|
||||
...(chainId ? { chainId } : {}),
|
||||
...(verifyingContract ? { verifyingContract } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hash of the exchange proxy EIP712 domain.
|
||||
*/
|
||||
export function getExchangeProxyEIP712DomainHash(chainId?: number, verifyingContract?: string): string {
|
||||
const domain = createExchangeProxyEIP712Domain(chainId, verifyingContract);
|
||||
return hexUtils.hash(
|
||||
hexUtils.concat(
|
||||
EXCHANGE_PROXY_DOMAIN_TYPEHASH,
|
||||
hexUtils.hash(hexUtils.toHex(Buffer.from(domain.name))),
|
||||
hexUtils.hash(hexUtils.toHex(Buffer.from(domain.version))),
|
||||
hexUtils.leftPad(domain.chainId),
|
||||
hexUtils.leftPad(domain.verifyingContract),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a complete EIP712 hash given a struct hash.
|
||||
*/
|
||||
export function getExchangeProxyEIP712Hash(structHash: string, chainId?: number, verifyingContract?: string): string {
|
||||
return hexUtils.hash(
|
||||
hexUtils.concat('0x1901', getExchangeProxyEIP712DomainHash(chainId, verifyingContract), structHash),
|
||||
);
|
||||
}
|
@@ -33,6 +33,9 @@ export * from './migration';
|
||||
export * from './nonce_utils';
|
||||
export * from './signed_call_data';
|
||||
export * from './signature_utils';
|
||||
export * from './orders';
|
||||
export * from './eip712_utils';
|
||||
export * from './revert_errors';
|
||||
export {
|
||||
AffiliateFeeTransformerContract,
|
||||
BridgeAdapterContract,
|
||||
@@ -49,6 +52,5 @@ export {
|
||||
WethTransformerContract,
|
||||
ZeroExContract,
|
||||
} from './wrappers';
|
||||
export * from './revert_errors';
|
||||
export { EIP712TypedData } from '@0x/types';
|
||||
export { SupportedProvider } from '@0x/subproviders';
|
||||
|
@@ -1,4 +1,6 @@
|
||||
import { SupportedProvider } from '@0x/subproviders';
|
||||
import { SimpleContractArtifact } from '@0x/types';
|
||||
import { NULL_ADDRESS } from '@0x/utils';
|
||||
import { TxData } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -8,6 +10,7 @@ import {
|
||||
InitialMigrationContract,
|
||||
IZeroExContract,
|
||||
MetaTransactionsFeatureContract,
|
||||
NativeOrdersFeatureContract,
|
||||
OwnableFeatureContract,
|
||||
SignatureValidatorFeatureContract,
|
||||
SimpleFunctionRegistryFeatureContract,
|
||||
@@ -26,6 +29,19 @@ export interface BootstrapFeatures {
|
||||
ownable: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Artifacts to use when deploying bootstrap features.
|
||||
*/
|
||||
export interface BootstrapFeatureArtifacts {
|
||||
registry: SimpleContractArtifact;
|
||||
ownable: SimpleContractArtifact;
|
||||
}
|
||||
|
||||
const DEFAULT_BOOTSTRAP_FEATURE_ARTIFACTS = {
|
||||
registry: artifacts.SimpleFunctionRegistryFeature,
|
||||
ownable: artifacts.OwnableFeature,
|
||||
};
|
||||
|
||||
/**
|
||||
* Deploy the minimum features of the Exchange Proxy.
|
||||
*/
|
||||
@@ -33,12 +49,17 @@ export async function deployBootstrapFeaturesAsync(
|
||||
provider: SupportedProvider,
|
||||
txDefaults: Partial<TxData>,
|
||||
features: Partial<BootstrapFeatures> = {},
|
||||
featureArtifacts: Partial<BootstrapFeatureArtifacts> = {},
|
||||
): Promise<BootstrapFeatures> {
|
||||
const _featureArtifacts = {
|
||||
...DEFAULT_BOOTSTRAP_FEATURE_ARTIFACTS,
|
||||
...featureArtifacts,
|
||||
};
|
||||
return {
|
||||
registry:
|
||||
features.registry ||
|
||||
(await SimpleFunctionRegistryFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.SimpleFunctionRegistryFeature,
|
||||
_featureArtifacts.registry,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
@@ -46,7 +67,7 @@ export async function deployBootstrapFeaturesAsync(
|
||||
ownable:
|
||||
features.ownable ||
|
||||
(await OwnableFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.OwnableFeature,
|
||||
_featureArtifacts.ownable,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
@@ -90,30 +111,73 @@ export interface FullFeatures extends BootstrapFeatures {
|
||||
transformERC20: string;
|
||||
signatureValidator: string;
|
||||
metaTransactions: string;
|
||||
nativeOrders: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra configuration options for a full migration of the Exchange Proxy.
|
||||
* Artifacts to use when deploying full features.
|
||||
*/
|
||||
export interface FullMigrationOpts {
|
||||
transformerDeployer: string;
|
||||
export interface FullFeatureArtifacts extends BootstrapFeatureArtifacts {
|
||||
tokenSpender: SimpleContractArtifact;
|
||||
transformERC20: SimpleContractArtifact;
|
||||
signatureValidator: SimpleContractArtifact;
|
||||
metaTransactions: SimpleContractArtifact;
|
||||
nativeOrders: SimpleContractArtifact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for deploying full features..
|
||||
*/
|
||||
export interface FullFeaturesDeployConfig {
|
||||
zeroExAddress: string;
|
||||
wethAddress: string;
|
||||
stakingAddress: string;
|
||||
protocolFeeMultiplier: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options for a full migration of the Exchange Proxy.
|
||||
*/
|
||||
export interface FullMigrationConfig extends FullFeaturesDeployConfig {
|
||||
transformerDeployer?: string;
|
||||
}
|
||||
|
||||
const DEFAULT_FULL_FEATURES_DEPLOY_CONFIG = {
|
||||
zeroExAddress: NULL_ADDRESS,
|
||||
wethAddress: NULL_ADDRESS,
|
||||
stakingAddress: NULL_ADDRESS,
|
||||
protocolFeeMultiplier: 70e3,
|
||||
};
|
||||
|
||||
const DEFAULT_FULL_FEATURES_ARTIFACTS = {
|
||||
tokenSpender: artifacts.TokenSpenderFeature,
|
||||
transformERC20: artifacts.TransformERC20Feature,
|
||||
signatureValidator: artifacts.SignatureValidatorFeature,
|
||||
metaTransactions: artifacts.MetaTransactionsFeature,
|
||||
nativeOrders: artifacts.NativeOrdersFeature,
|
||||
};
|
||||
|
||||
/**
|
||||
* Deploy all the features for a full Exchange Proxy.
|
||||
*/
|
||||
export async function deployFullFeaturesAsync(
|
||||
provider: SupportedProvider,
|
||||
txDefaults: Partial<TxData>,
|
||||
zeroExAddress: string,
|
||||
config: Partial<FullFeaturesDeployConfig> = {},
|
||||
features: Partial<FullFeatures> = {},
|
||||
featureArtifacts: Partial<FullFeatureArtifacts> = {},
|
||||
): Promise<FullFeatures> {
|
||||
const _config = { ...DEFAULT_FULL_FEATURES_DEPLOY_CONFIG, ...config };
|
||||
const _featureArtifacts = {
|
||||
...DEFAULT_FULL_FEATURES_ARTIFACTS,
|
||||
...featureArtifacts,
|
||||
};
|
||||
return {
|
||||
...(await deployBootstrapFeaturesAsync(provider, txDefaults)),
|
||||
tokenSpender:
|
||||
features.tokenSpender ||
|
||||
(await TokenSpenderFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TokenSpenderFeature,
|
||||
_featureArtifacts.tokenSpender,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
@@ -121,7 +185,7 @@ export async function deployFullFeaturesAsync(
|
||||
transformERC20:
|
||||
features.transformERC20 ||
|
||||
(await TransformERC20FeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TransformERC20Feature,
|
||||
_featureArtifacts.transformERC20,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
@@ -129,7 +193,7 @@ export async function deployFullFeaturesAsync(
|
||||
signatureValidator:
|
||||
features.signatureValidator ||
|
||||
(await SignatureValidatorFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.SignatureValidatorFeature,
|
||||
_featureArtifacts.signatureValidator,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
@@ -137,11 +201,23 @@ export async function deployFullFeaturesAsync(
|
||||
metaTransactions:
|
||||
features.metaTransactions ||
|
||||
(await MetaTransactionsFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.MetaTransactionsFeature,
|
||||
_featureArtifacts.metaTransactions,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
zeroExAddress,
|
||||
_config.zeroExAddress,
|
||||
)).address,
|
||||
nativeOrders:
|
||||
features.nativeOrders ||
|
||||
(await NativeOrdersFeatureContract.deployFrom0xArtifactAsync(
|
||||
_featureArtifacts.nativeOrders,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
_config.zeroExAddress,
|
||||
_config.wethAddress,
|
||||
_config.stakingAddress,
|
||||
_config.protocolFeeMultiplier,
|
||||
)).address,
|
||||
};
|
||||
}
|
||||
@@ -154,7 +230,8 @@ export async function fullMigrateAsync(
|
||||
provider: SupportedProvider,
|
||||
txDefaults: Partial<TxData>,
|
||||
features: Partial<FullFeatures> = {},
|
||||
opts: Partial<FullMigrationOpts> = {},
|
||||
config: Partial<FullMigrationConfig> = {},
|
||||
featureArtifacts: Partial<FullFeatureArtifacts> = {},
|
||||
): Promise<IZeroExContract> {
|
||||
const migrator = await FullMigrationContract.deployFrom0xArtifactAsync(
|
||||
artifacts.FullMigration,
|
||||
@@ -170,11 +247,12 @@ export async function fullMigrateAsync(
|
||||
artifacts,
|
||||
await migrator.getBootstrapper().callAsync(),
|
||||
);
|
||||
const _features = await deployFullFeaturesAsync(provider, txDefaults, zeroEx.address, features);
|
||||
const _opts = {
|
||||
const _config = { ...config, zeroExAddress: zeroEx.address };
|
||||
const _features = await deployFullFeaturesAsync(provider, txDefaults, _config, features, featureArtifacts);
|
||||
const migrateOpts = {
|
||||
transformerDeployer: txDefaults.from as string,
|
||||
...opts,
|
||||
..._config,
|
||||
};
|
||||
await migrator.initializeZeroEx(owner, zeroEx.address, _features, _opts).awaitTransactionSuccessAsync();
|
||||
await migrator.migrateZeroEx(owner, zeroEx.address, _features, migrateOpts).awaitTransactionSuccessAsync();
|
||||
return new IZeroExContract(zeroEx.address, provider, txDefaults);
|
||||
}
|
||||
|
333
contracts/zero-ex/src/orders.ts
Normal file
333
contracts/zero-ex/src/orders.ts
Normal file
@@ -0,0 +1,333 @@
|
||||
// tslint:disable: max-classes-per-file
|
||||
import { SupportedProvider } from '@0x/subproviders';
|
||||
import { EIP712TypedData } from '@0x/types';
|
||||
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
|
||||
|
||||
import { createExchangeProxyEIP712Domain, EIP712_DOMAIN_PARAMETERS, getExchangeProxyEIP712Hash } from './eip712_utils';
|
||||
import {
|
||||
eip712SignTypedDataWithKey,
|
||||
eip712SignTypedDataWithProviderAsync,
|
||||
ethSignHashWithKey,
|
||||
ethSignHashWithProviderAsync,
|
||||
Signature,
|
||||
SignatureType,
|
||||
} from './signature_utils';
|
||||
|
||||
const ZERO = new BigNumber(0);
|
||||
const COMMON_ORDER_DEFAULT_VALUES = {
|
||||
makerToken: NULL_ADDRESS,
|
||||
takerToken: NULL_ADDRESS,
|
||||
makerAmount: ZERO,
|
||||
takerAmount: ZERO,
|
||||
maker: NULL_ADDRESS,
|
||||
pool: hexUtils.leftPad(0),
|
||||
expiry: ZERO,
|
||||
salt: ZERO,
|
||||
chainId: 1,
|
||||
verifyingContract: '0xdef1c0ded9bec7f1a1670819833240f027b25eff',
|
||||
};
|
||||
const LIMIT_ORDER_DEFAULT_VALUES = {
|
||||
...COMMON_ORDER_DEFAULT_VALUES,
|
||||
takerTokenFeeAmount: ZERO,
|
||||
taker: NULL_ADDRESS,
|
||||
sender: NULL_ADDRESS,
|
||||
feeRecipient: NULL_ADDRESS,
|
||||
};
|
||||
const RFQ_ORDER_DEFAULT_VALUES = {
|
||||
...COMMON_ORDER_DEFAULT_VALUES,
|
||||
txOrigin: NULL_ADDRESS,
|
||||
};
|
||||
|
||||
export type CommonOrderFields = typeof COMMON_ORDER_DEFAULT_VALUES;
|
||||
export type LimitOrderFields = typeof LIMIT_ORDER_DEFAULT_VALUES;
|
||||
export type RfqOrderFields = typeof RFQ_ORDER_DEFAULT_VALUES;
|
||||
|
||||
export enum OrderStatus {
|
||||
Invalid = 0,
|
||||
Fillable = 1,
|
||||
Filled = 2,
|
||||
Cancelled = 3,
|
||||
Expired = 4,
|
||||
}
|
||||
|
||||
export interface OrderInfo {
|
||||
status: OrderStatus;
|
||||
orderHash: string;
|
||||
takerTokenFilledAmount: BigNumber;
|
||||
}
|
||||
|
||||
export abstract class OrderBase {
|
||||
public makerToken: string;
|
||||
public takerToken: string;
|
||||
public makerAmount: BigNumber;
|
||||
public takerAmount: BigNumber;
|
||||
public maker: string;
|
||||
public pool: string;
|
||||
public expiry: BigNumber;
|
||||
public salt: BigNumber;
|
||||
public chainId: number;
|
||||
public verifyingContract: string;
|
||||
|
||||
protected constructor(fields: Partial<CommonOrderFields> = {}) {
|
||||
const _fields = { ...COMMON_ORDER_DEFAULT_VALUES, ...fields };
|
||||
this.makerToken = _fields.makerToken;
|
||||
this.takerToken = _fields.takerToken;
|
||||
this.makerAmount = _fields.makerAmount;
|
||||
this.takerAmount = _fields.takerAmount;
|
||||
this.maker = _fields.maker;
|
||||
this.pool = _fields.pool;
|
||||
this.expiry = _fields.expiry;
|
||||
this.salt = _fields.salt;
|
||||
this.chainId = _fields.chainId;
|
||||
this.verifyingContract = _fields.verifyingContract;
|
||||
}
|
||||
|
||||
public abstract getStructHash(): string;
|
||||
public abstract getEIP712TypedData(): EIP712TypedData;
|
||||
|
||||
public getHash(): string {
|
||||
return getExchangeProxyEIP712Hash(this.getStructHash(), this.chainId, this.verifyingContract);
|
||||
}
|
||||
|
||||
public async getSignatureWithProviderAsync(
|
||||
provider: SupportedProvider,
|
||||
type: SignatureType = SignatureType.EthSign,
|
||||
): Promise<Signature> {
|
||||
switch (type) {
|
||||
case SignatureType.EIP712:
|
||||
return eip712SignTypedDataWithProviderAsync(this.getEIP712TypedData(), this.maker, provider);
|
||||
case SignatureType.EthSign:
|
||||
return ethSignHashWithProviderAsync(this.getHash(), this.maker, provider);
|
||||
default:
|
||||
throw new Error(`Cannot sign with signature type: ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
public getSignatureWithKey(key: string, type: SignatureType = SignatureType.EthSign): Signature {
|
||||
switch (type) {
|
||||
case SignatureType.EIP712:
|
||||
return eip712SignTypedDataWithKey(this.getEIP712TypedData(), key);
|
||||
case SignatureType.EthSign:
|
||||
return ethSignHashWithKey(this.getHash(), key);
|
||||
default:
|
||||
throw new Error(`Cannot sign with signature type: ${type}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class LimitOrder extends OrderBase {
|
||||
public static readonly TYPE_HASH = hexUtils.hash(
|
||||
hexUtils.toHex(
|
||||
Buffer.from(
|
||||
[
|
||||
'LimitOrder(',
|
||||
[
|
||||
'address makerToken',
|
||||
'address takerToken',
|
||||
'uint128 makerAmount',
|
||||
'uint128 takerAmount',
|
||||
'uint128 takerTokenFeeAmount',
|
||||
'address maker',
|
||||
'address taker',
|
||||
'address sender',
|
||||
'address feeRecipient',
|
||||
'bytes32 pool',
|
||||
'uint64 expiry',
|
||||
'uint256 salt',
|
||||
].join(','),
|
||||
')',
|
||||
].join(''),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
public takerTokenFeeAmount: BigNumber;
|
||||
public taker: string;
|
||||
public sender: string;
|
||||
public feeRecipient: string;
|
||||
|
||||
constructor(fields: Partial<LimitOrderFields> = {}) {
|
||||
const _fields = { ...LIMIT_ORDER_DEFAULT_VALUES, ...fields };
|
||||
super(_fields);
|
||||
this.takerTokenFeeAmount = _fields.takerTokenFeeAmount;
|
||||
this.taker = _fields.taker;
|
||||
this.sender = _fields.sender;
|
||||
this.feeRecipient = _fields.feeRecipient;
|
||||
}
|
||||
|
||||
public clone(fields: Partial<LimitOrderFields> = {}): LimitOrder {
|
||||
return new LimitOrder({
|
||||
makerToken: this.makerToken,
|
||||
takerToken: this.takerToken,
|
||||
makerAmount: this.makerAmount,
|
||||
takerAmount: this.takerAmount,
|
||||
takerTokenFeeAmount: this.takerTokenFeeAmount,
|
||||
maker: this.maker,
|
||||
taker: this.taker,
|
||||
sender: this.sender,
|
||||
feeRecipient: this.feeRecipient,
|
||||
pool: this.pool,
|
||||
expiry: this.expiry,
|
||||
salt: this.salt,
|
||||
chainId: this.chainId,
|
||||
verifyingContract: this.verifyingContract,
|
||||
...fields,
|
||||
});
|
||||
}
|
||||
|
||||
public getStructHash(): string {
|
||||
return hexUtils.hash(
|
||||
hexUtils.concat(
|
||||
hexUtils.leftPad(LimitOrder.TYPE_HASH),
|
||||
hexUtils.leftPad(this.makerToken),
|
||||
hexUtils.leftPad(this.takerToken),
|
||||
hexUtils.leftPad(this.makerAmount),
|
||||
hexUtils.leftPad(this.takerAmount),
|
||||
hexUtils.leftPad(this.takerTokenFeeAmount),
|
||||
hexUtils.leftPad(this.maker),
|
||||
hexUtils.leftPad(this.taker),
|
||||
hexUtils.leftPad(this.sender),
|
||||
hexUtils.leftPad(this.feeRecipient),
|
||||
hexUtils.leftPad(this.pool),
|
||||
hexUtils.leftPad(this.expiry),
|
||||
hexUtils.leftPad(this.salt),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public getEIP712TypedData(): EIP712TypedData {
|
||||
return {
|
||||
types: {
|
||||
EIP712Domain: EIP712_DOMAIN_PARAMETERS,
|
||||
LimitOrder: [
|
||||
{ type: 'address', name: 'makerToken' },
|
||||
{ type: 'address', name: 'takerToken' },
|
||||
{ type: 'uint128', name: 'makerAmount' },
|
||||
{ type: 'uint128', name: 'takerAmount' },
|
||||
{ type: 'uint128', name: 'takerTokenFeeAmount' },
|
||||
{ type: 'address', name: 'maker' },
|
||||
{ type: 'address', name: 'taker' },
|
||||
{ type: 'address', name: 'sender' },
|
||||
{ type: 'address', name: 'feeRecipient' },
|
||||
{ type: 'bytes32', name: 'pool' },
|
||||
{ type: 'uint64', name: 'expiry' },
|
||||
{ type: 'uint256', name: 'salt' },
|
||||
],
|
||||
},
|
||||
domain: createExchangeProxyEIP712Domain(this.chainId, this.verifyingContract) as any,
|
||||
primaryType: 'LimitOrder',
|
||||
message: {
|
||||
makerToken: this.makerToken,
|
||||
takerToken: this.takerToken,
|
||||
makerAmount: this.makerAmount.toString(10),
|
||||
takerAmount: this.takerAmount.toString(10),
|
||||
takerTokenFeeAmount: this.takerTokenFeeAmount.toString(10),
|
||||
maker: this.maker,
|
||||
taker: this.taker,
|
||||
sender: this.sender,
|
||||
feeRecipient: this.feeRecipient,
|
||||
pool: this.pool,
|
||||
expiry: this.expiry.toString(10),
|
||||
salt: this.salt.toString(10),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class RfqOrder extends OrderBase {
|
||||
public static readonly TYPE_HASH = hexUtils.hash(
|
||||
hexUtils.toHex(
|
||||
Buffer.from(
|
||||
[
|
||||
'RfqOrder(',
|
||||
[
|
||||
'address makerToken',
|
||||
'address takerToken',
|
||||
'uint128 makerAmount',
|
||||
'uint128 takerAmount',
|
||||
'address maker',
|
||||
'address txOrigin',
|
||||
'bytes32 pool',
|
||||
'uint64 expiry',
|
||||
'uint256 salt',
|
||||
].join(','),
|
||||
')',
|
||||
].join(''),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
public txOrigin: string;
|
||||
|
||||
constructor(fields: Partial<RfqOrderFields> = {}) {
|
||||
const _fields = { ...RFQ_ORDER_DEFAULT_VALUES, ...fields };
|
||||
super(_fields);
|
||||
this.txOrigin = _fields.txOrigin;
|
||||
}
|
||||
|
||||
public clone(fields: Partial<RfqOrderFields> = {}): RfqOrder {
|
||||
return new RfqOrder({
|
||||
makerToken: this.makerToken,
|
||||
takerToken: this.takerToken,
|
||||
makerAmount: this.makerAmount,
|
||||
takerAmount: this.takerAmount,
|
||||
maker: this.maker,
|
||||
txOrigin: this.txOrigin,
|
||||
pool: this.pool,
|
||||
expiry: this.expiry,
|
||||
salt: this.salt,
|
||||
chainId: this.chainId,
|
||||
verifyingContract: this.verifyingContract,
|
||||
...fields,
|
||||
});
|
||||
}
|
||||
|
||||
public getStructHash(): string {
|
||||
return hexUtils.hash(
|
||||
hexUtils.concat(
|
||||
hexUtils.leftPad(RfqOrder.TYPE_HASH),
|
||||
hexUtils.leftPad(this.makerToken),
|
||||
hexUtils.leftPad(this.takerToken),
|
||||
hexUtils.leftPad(this.makerAmount),
|
||||
hexUtils.leftPad(this.takerAmount),
|
||||
hexUtils.leftPad(this.maker),
|
||||
hexUtils.leftPad(this.txOrigin),
|
||||
hexUtils.leftPad(this.pool),
|
||||
hexUtils.leftPad(this.expiry),
|
||||
hexUtils.leftPad(this.salt),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public getEIP712TypedData(): EIP712TypedData {
|
||||
return {
|
||||
types: {
|
||||
EIP712Domain: EIP712_DOMAIN_PARAMETERS,
|
||||
RfqOrder: [
|
||||
{ type: 'address', name: 'makerToken' },
|
||||
{ type: 'address', name: 'takerToken' },
|
||||
{ type: 'uint128', name: 'makerAmount' },
|
||||
{ type: 'uint128', name: 'takerAmount' },
|
||||
{ type: 'address', name: 'maker' },
|
||||
{ type: 'address', name: 'txOrigin' },
|
||||
{ type: 'bytes32', name: 'pool' },
|
||||
{ type: 'uint64', name: 'expiry' },
|
||||
{ type: 'uint256', name: 'salt' },
|
||||
],
|
||||
},
|
||||
domain: createExchangeProxyEIP712Domain(this.chainId, this.verifyingContract) as any,
|
||||
primaryType: 'RfqOrder',
|
||||
message: {
|
||||
makerToken: this.makerToken,
|
||||
takerToken: this.takerToken,
|
||||
makerAmount: this.makerAmount.toString(10),
|
||||
takerAmount: this.takerAmount.toString(10),
|
||||
maker: this.maker,
|
||||
txOrigin: this.txOrigin,
|
||||
pool: this.pool,
|
||||
expiry: this.expiry.toString(10),
|
||||
salt: this.salt.toString(10),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
@@ -1,7 +1,9 @@
|
||||
// TODO(dorothy-zbornak): Move these into `@0x/protocol-utils` whenever that
|
||||
// becomes a thing.
|
||||
// tslint:disable:max-classes-per-file
|
||||
import { RevertError } from '@0x/utils';
|
||||
import { Numberish, RevertError } from '@0x/utils';
|
||||
|
||||
import { OrderStatus } from './orders';
|
||||
|
||||
export enum SignatureValidationErrorCodes {
|
||||
AlwaysInvalid = 0,
|
||||
@@ -12,7 +14,6 @@ export enum SignatureValidationErrorCodes {
|
||||
BadSignatureData = 5,
|
||||
}
|
||||
|
||||
// tslint:disable:max-classes-per-file
|
||||
export class SignatureValidationError extends RevertError {
|
||||
constructor(code?: SignatureValidationErrorCodes, hash?: string) {
|
||||
super('SignatureValidationError', 'SignatureValidationError(uint8 code, bytes32 hash)', {
|
||||
@@ -22,7 +23,125 @@ export class SignatureValidationError extends RevertError {
|
||||
}
|
||||
}
|
||||
|
||||
const types = [SignatureValidationError];
|
||||
export class ProtocolFeeRefundFailed extends RevertError {
|
||||
constructor(receiver?: string, refundAmount?: Numberish) {
|
||||
super('ProtocolFeeRefundFailed', 'ProtocolFeeRefundFailed(address receiver, uint256 refundAmount)', {
|
||||
receiver,
|
||||
refundAmount,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class OrderNotFillableByOriginError extends RevertError {
|
||||
constructor(orderHash?: string, txOrigin?: string, orderTxOrigin?: string) {
|
||||
super(
|
||||
'OrderNotFillableByOriginError',
|
||||
'OrderNotFillableByOriginError(bytes32 orderHash, address txOrigin, address orderTxOrigin)',
|
||||
{
|
||||
orderHash,
|
||||
txOrigin,
|
||||
orderTxOrigin,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class OrderNotFillableError extends RevertError {
|
||||
constructor(orderHash?: string, orderStatus?: OrderStatus) {
|
||||
super('OrderNotFillableError', 'OrderNotFillableError(bytes32 orderHash, uint8 orderStatus)', {
|
||||
orderHash,
|
||||
orderStatus,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class OrderNotSignedByMakerError extends RevertError {
|
||||
constructor(orderHash?: string, signer?: string, maker?: string) {
|
||||
super(
|
||||
'OrderNotSignedByMakerError',
|
||||
'OrderNotSignedByMakerError(bytes32 orderHash, address signer, address maker)',
|
||||
{
|
||||
orderHash,
|
||||
signer,
|
||||
maker,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class OrderNotFillableBySenderError extends RevertError {
|
||||
constructor(orderHash?: string, sender?: string, orderSender?: string) {
|
||||
super(
|
||||
'OrderNotFillableBySenderError',
|
||||
'OrderNotFillableBySenderError(bytes32 orderHash, address sender, address orderSender)',
|
||||
{
|
||||
orderHash,
|
||||
sender,
|
||||
orderSender,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class OrderNotFillableByTakerError extends RevertError {
|
||||
constructor(orderHash?: string, taker?: string, orderTaker?: string) {
|
||||
super(
|
||||
'OrderNotFillableByTakerError',
|
||||
'OrderNotFillableByTakerError(bytes32 orderHash, address taker, address orderTaker)',
|
||||
{
|
||||
orderHash,
|
||||
taker,
|
||||
orderTaker,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class CancelSaltTooLowError extends RevertError {
|
||||
constructor(minValidSalt?: Numberish, oldMinValidSalt?: Numberish) {
|
||||
super('CancelSaltTooLowError', 'CancelSaltTooLowError(uint256 minValidSalt, uint256 oldMinValidSalt)', {
|
||||
minValidSalt,
|
||||
oldMinValidSalt,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class FillOrKillFailedError extends RevertError {
|
||||
constructor(orderHash?: string, takerTokenFilledAmount?: Numberish, takerTokenFillAmount?: Numberish) {
|
||||
super(
|
||||
'FillOrKillFailedError',
|
||||
'FillOrKillFailedError(bytes32 orderHash, uint256 takerTokenFilledAmount, uint256 takerTokenFillAmount)',
|
||||
{
|
||||
orderHash,
|
||||
takerTokenFilledAmount,
|
||||
takerTokenFillAmount,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class OnlyOrderMakerAllowed extends RevertError {
|
||||
constructor(orderHash?: string, sender?: string, maker?: string) {
|
||||
super('OnlyOrderMakerAllowed', 'OnlyOrderMakerAllowed(bytes32 orderHash, address sender, address maker)', {
|
||||
orderHash,
|
||||
sender,
|
||||
maker,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const types = [
|
||||
SignatureValidationError,
|
||||
ProtocolFeeRefundFailed,
|
||||
OrderNotFillableByOriginError,
|
||||
OrderNotFillableError,
|
||||
OrderNotSignedByMakerError,
|
||||
OrderNotFillableBySenderError,
|
||||
OrderNotFillableByTakerError,
|
||||
CancelSaltTooLowError,
|
||||
FillOrKillFailedError,
|
||||
OnlyOrderMakerAllowed,
|
||||
];
|
||||
|
||||
// Register the types we've defined.
|
||||
for (const type of types) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { signatureUtils } from '@0x/order-utils';
|
||||
import { SupportedProvider } from '@0x/subproviders';
|
||||
import { EIP712TypedData } from '@0x/types';
|
||||
import { hexUtils, signTypedDataUtils } from '@0x/utils';
|
||||
import { hexUtils, providerUtils, signTypedDataUtils } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as ethjs from 'ethereumjs-util';
|
||||
|
||||
/**
|
||||
@@ -33,15 +33,17 @@ export interface Signature extends ECSignature {
|
||||
/**
|
||||
* Sign a hash with the EthSign signature type on a provider.
|
||||
*/
|
||||
export async function ethSignHashFromProviderAsync(
|
||||
signer: string,
|
||||
export async function ethSignHashWithProviderAsync(
|
||||
hash: string,
|
||||
signer: string,
|
||||
provider: SupportedProvider,
|
||||
): Promise<Signature> {
|
||||
const signatureBytes = await signatureUtils.ecSignHashAsync(provider, hash, signer);
|
||||
const parsed = parsePackedSignatureBytes(signatureBytes);
|
||||
assertSignatureType(parsed, SignatureType.EthSign);
|
||||
return parsed;
|
||||
const w3w = new Web3Wrapper(providerUtils.standardizeOrThrow(provider));
|
||||
const rpcSig = await w3w.signMessageAsync(signer, hash);
|
||||
return {
|
||||
...parseRpcSignature(rpcSig),
|
||||
signatureType: SignatureType.EthSign,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,6 +59,22 @@ export function ethSignHashWithKey(hash: string, key: string): Signature {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a typed data object with the EIP712 signature type on a provider.
|
||||
*/
|
||||
export async function eip712SignTypedDataWithProviderAsync(
|
||||
data: EIP712TypedData,
|
||||
signer: string,
|
||||
provider: SupportedProvider,
|
||||
): Promise<Signature> {
|
||||
const w3w = new Web3Wrapper(providerUtils.standardizeOrThrow(provider));
|
||||
const rpcSig = await w3w.signTypedDataAsync(signer, data);
|
||||
return {
|
||||
...parseRpcSignature(rpcSig),
|
||||
signatureType: SignatureType.EIP712,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a typed data object with the EIP712 signature type, given a private key.
|
||||
*/
|
||||
@@ -90,24 +108,34 @@ export function ecSignHashWithKey(hash: string, key: string): ECSignature {
|
||||
};
|
||||
}
|
||||
|
||||
function assertSignatureType(signature: Signature, expectedType: SignatureType): void {
|
||||
if (signature.signatureType !== expectedType) {
|
||||
throw new Error(`Expected signature type to be ${expectedType} but received ${signature.signatureType}.`);
|
||||
// Parse a hex signature returned by an RPC call into an `ECSignature`.
|
||||
function parseRpcSignature(rpcSig: string): ECSignature {
|
||||
if (hexUtils.size(rpcSig) !== 65) {
|
||||
throw new Error(`Invalid RPC signature length: "${rpcSig}"`);
|
||||
}
|
||||
}
|
||||
|
||||
function parsePackedSignatureBytes(signatureBytes: string): Signature {
|
||||
if (hexUtils.size(signatureBytes) !== 66) {
|
||||
throw new Error(`Expected packed signatureBytes to be 66 bytes long: ${signatureBytes}`);
|
||||
// Some providers encode V as 0,1 instead of 27,28.
|
||||
const VALID_V_VALUES = [0, 1, 27, 28];
|
||||
// Some providers return the signature packed as V,R,S and others R,S,V.
|
||||
// Try to guess which encoding it is (with a slight preference for R,S,V).
|
||||
let v = parseInt(rpcSig.slice(-2), 16);
|
||||
if (VALID_V_VALUES.includes(v)) {
|
||||
// Format is R,S,V
|
||||
v = v >= 27 ? v : v + 27;
|
||||
return {
|
||||
r: hexUtils.slice(rpcSig, 0, 32),
|
||||
s: hexUtils.slice(rpcSig, 32, 64),
|
||||
v,
|
||||
};
|
||||
}
|
||||
const typeId = parseInt(signatureBytes.slice(-2), 16) as SignatureType;
|
||||
if (!Object.values(SignatureType).includes(typeId)) {
|
||||
throw new Error(`Invalid signatureBytes type ID detected: ${typeId}`);
|
||||
// Format should be V,R,S
|
||||
v = parseInt(rpcSig.slice(2, 4), 16);
|
||||
if (!VALID_V_VALUES.includes(v)) {
|
||||
throw new Error(`Cannot determine RPC signature layout from V value: "${rpcSig}"`);
|
||||
}
|
||||
v = v >= 27 ? v : v + 27;
|
||||
return {
|
||||
signatureType: typeId,
|
||||
v: parseInt(signatureBytes.slice(2, 4), 16),
|
||||
r: hexUtils.slice(signatureBytes, 1, 33),
|
||||
s: hexUtils.slice(signatureBytes, 33),
|
||||
v,
|
||||
r: hexUtils.slice(rpcSig, 1, 33),
|
||||
s: hexUtils.slice(rpcSig, 33, 65),
|
||||
};
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ export * from '../generated-wrappers/full_migration';
|
||||
export * from '../generated-wrappers/i_allowance_target';
|
||||
export * from '../generated-wrappers/i_erc20_transformer';
|
||||
export * from '../generated-wrappers/i_flash_wallet';
|
||||
export * from '../generated-wrappers/i_liquidity_provider_feature';
|
||||
export * from '../generated-wrappers/i_native_orders_feature';
|
||||
export * from '../generated-wrappers/i_ownable_feature';
|
||||
export * from '../generated-wrappers/i_simple_function_registry_feature';
|
||||
export * from '../generated-wrappers/i_token_spender_feature';
|
||||
@@ -19,6 +21,7 @@ export * from '../generated-wrappers/initial_migration';
|
||||
export * from '../generated-wrappers/liquidity_provider_feature';
|
||||
export * from '../generated-wrappers/log_metadata_transformer';
|
||||
export * from '../generated-wrappers/meta_transactions_feature';
|
||||
export * from '../generated-wrappers/native_orders_feature';
|
||||
export * from '../generated-wrappers/ownable_feature';
|
||||
export * from '../generated-wrappers/pay_taker_transformer';
|
||||
export * from '../generated-wrappers/signature_validator_feature';
|
||||
|
@@ -28,7 +28,9 @@ import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json';
|
||||
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
|
||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
||||
import * as ILiquidityProviderFeature from '../test/generated-artifacts/ILiquidityProviderFeature.json';
|
||||
import * as ILiquidityProviderSandbox from '../test/generated-artifacts/ILiquidityProviderSandbox.json';
|
||||
import * as IMetaTransactionsFeature from '../test/generated-artifacts/IMetaTransactionsFeature.json';
|
||||
import * as INativeOrdersFeature from '../test/generated-artifacts/INativeOrdersFeature.json';
|
||||
import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json';
|
||||
import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json';
|
||||
import * as ISignatureValidatorFeature from '../test/generated-artifacts/ISignatureValidatorFeature.json';
|
||||
@@ -43,10 +45,12 @@ import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json';
|
||||
import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json';
|
||||
import * as LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.json';
|
||||
import * as LibLiquidityProviderRichErrors from '../test/generated-artifacts/LibLiquidityProviderRichErrors.json';
|
||||
import * as LibLiquidityProviderStorage from '../test/generated-artifacts/LibLiquidityProviderStorage.json';
|
||||
import * as LibMetaTransactionsRichErrors from '../test/generated-artifacts/LibMetaTransactionsRichErrors.json';
|
||||
import * as LibMetaTransactionsStorage from '../test/generated-artifacts/LibMetaTransactionsStorage.json';
|
||||
import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json';
|
||||
import * as LibNativeOrder from '../test/generated-artifacts/LibNativeOrder.json';
|
||||
import * as LibNativeOrdersRichErrors from '../test/generated-artifacts/LibNativeOrdersRichErrors.json';
|
||||
import * as LibNativeOrdersStorage from '../test/generated-artifacts/LibNativeOrdersStorage.json';
|
||||
import * as LibOrderHash from '../test/generated-artifacts/LibOrderHash.json';
|
||||
import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json';
|
||||
import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json';
|
||||
@@ -66,6 +70,7 @@ import * as LibTransformERC20RichErrors from '../test/generated-artifacts/LibTra
|
||||
import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json';
|
||||
import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json';
|
||||
import * as LiquidityProviderFeature from '../test/generated-artifacts/LiquidityProviderFeature.json';
|
||||
import * as LiquidityProviderSandbox from '../test/generated-artifacts/LiquidityProviderSandbox.json';
|
||||
import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json';
|
||||
import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json';
|
||||
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
|
||||
@@ -81,6 +86,7 @@ import * as MixinSushiswap from '../test/generated-artifacts/MixinSushiswap.json
|
||||
import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json';
|
||||
import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json';
|
||||
import * as MixinZeroExBridge from '../test/generated-artifacts/MixinZeroExBridge.json';
|
||||
import * as NativeOrdersFeature from '../test/generated-artifacts/NativeOrdersFeature.json';
|
||||
import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json';
|
||||
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
|
||||
import * as SignatureValidatorFeature from '../test/generated-artifacts/SignatureValidatorFeature.json';
|
||||
@@ -91,15 +97,18 @@ import * as TestDelegateCaller from '../test/generated-artifacts/TestDelegateCal
|
||||
import * as TestFillQuoteTransformerBridge from '../test/generated-artifacts/TestFillQuoteTransformerBridge.json';
|
||||
import * as TestFillQuoteTransformerExchange from '../test/generated-artifacts/TestFillQuoteTransformerExchange.json';
|
||||
import * as TestFillQuoteTransformerHost from '../test/generated-artifacts/TestFillQuoteTransformerHost.json';
|
||||
import * as TestFixinProtocolFees from '../test/generated-artifacts/TestFixinProtocolFees.json';
|
||||
import * as TestFullMigration from '../test/generated-artifacts/TestFullMigration.json';
|
||||
import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.json';
|
||||
import * as TestLibNativeOrder from '../test/generated-artifacts/TestLibNativeOrder.json';
|
||||
import * as TestLibSignature from '../test/generated-artifacts/TestLibSignature.json';
|
||||
import * as TestLibTokenSpender from '../test/generated-artifacts/TestLibTokenSpender.json';
|
||||
import * as TestLiquidityProvider from '../test/generated-artifacts/TestLiquidityProvider.json';
|
||||
import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json';
|
||||
import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json';
|
||||
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
|
||||
import * as TestMintTokenERC20Transformer from '../test/generated-artifacts/TestMintTokenERC20Transformer.json';
|
||||
import * as TestProtocolFees from '../test/generated-artifacts/TestProtocolFees.json';
|
||||
import * as TestNativeOrdersFeature from '../test/generated-artifacts/TestNativeOrdersFeature.json';
|
||||
import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json';
|
||||
import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json';
|
||||
import * as TestStaking from '../test/generated-artifacts/TestStaking.json';
|
||||
@@ -125,6 +134,7 @@ export const artifacts = {
|
||||
LibCommonRichErrors: LibCommonRichErrors as ContractArtifact,
|
||||
LibLiquidityProviderRichErrors: LibLiquidityProviderRichErrors as ContractArtifact,
|
||||
LibMetaTransactionsRichErrors: LibMetaTransactionsRichErrors as ContractArtifact,
|
||||
LibNativeOrdersRichErrors: LibNativeOrdersRichErrors as ContractArtifact,
|
||||
LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact,
|
||||
LibProxyRichErrors: LibProxyRichErrors as ContractArtifact,
|
||||
LibSignatureRichErrors: LibSignatureRichErrors as ContractArtifact,
|
||||
@@ -137,12 +147,15 @@ export const artifacts = {
|
||||
FlashWallet: FlashWallet as ContractArtifact,
|
||||
IAllowanceTarget: IAllowanceTarget as ContractArtifact,
|
||||
IFlashWallet: IFlashWallet as ContractArtifact,
|
||||
ILiquidityProviderSandbox: ILiquidityProviderSandbox as ContractArtifact,
|
||||
LiquidityProviderSandbox: LiquidityProviderSandbox as ContractArtifact,
|
||||
TransformerDeployer: TransformerDeployer as ContractArtifact,
|
||||
BootstrapFeature: BootstrapFeature as ContractArtifact,
|
||||
IBootstrapFeature: IBootstrapFeature as ContractArtifact,
|
||||
IFeature: IFeature as ContractArtifact,
|
||||
ILiquidityProviderFeature: ILiquidityProviderFeature as ContractArtifact,
|
||||
IMetaTransactionsFeature: IMetaTransactionsFeature as ContractArtifact,
|
||||
INativeOrdersFeature: INativeOrdersFeature as ContractArtifact,
|
||||
IOwnableFeature: IOwnableFeature as ContractArtifact,
|
||||
ISignatureValidatorFeature: ISignatureValidatorFeature as ContractArtifact,
|
||||
ISimpleFunctionRegistryFeature: ISimpleFunctionRegistryFeature as ContractArtifact,
|
||||
@@ -151,12 +164,14 @@ export const artifacts = {
|
||||
IUniswapFeature: IUniswapFeature as ContractArtifact,
|
||||
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
|
||||
MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact,
|
||||
NativeOrdersFeature: NativeOrdersFeature as ContractArtifact,
|
||||
OwnableFeature: OwnableFeature as ContractArtifact,
|
||||
SignatureValidatorFeature: SignatureValidatorFeature as ContractArtifact,
|
||||
SimpleFunctionRegistryFeature: SimpleFunctionRegistryFeature as ContractArtifact,
|
||||
TokenSpenderFeature: TokenSpenderFeature as ContractArtifact,
|
||||
TransformERC20Feature: TransformERC20Feature as ContractArtifact,
|
||||
UniswapFeature: UniswapFeature as ContractArtifact,
|
||||
LibNativeOrder: LibNativeOrder as ContractArtifact,
|
||||
LibSignature: LibSignature as ContractArtifact,
|
||||
LibSignedCallData: LibSignedCallData as ContractArtifact,
|
||||
LibTokenSpender: LibTokenSpender as ContractArtifact,
|
||||
@@ -168,8 +183,8 @@ export const artifacts = {
|
||||
InitialMigration: InitialMigration as ContractArtifact,
|
||||
LibBootstrap: LibBootstrap as ContractArtifact,
|
||||
LibMigrate: LibMigrate as ContractArtifact,
|
||||
LibLiquidityProviderStorage: LibLiquidityProviderStorage as ContractArtifact,
|
||||
LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact,
|
||||
LibNativeOrdersStorage: LibNativeOrdersStorage as ContractArtifact,
|
||||
LibOwnableStorage: LibOwnableStorage as ContractArtifact,
|
||||
LibProxyStorage: LibProxyStorage as ContractArtifact,
|
||||
LibReentrancyGuardStorage: LibReentrancyGuardStorage as ContractArtifact,
|
||||
@@ -213,15 +228,18 @@ export const artifacts = {
|
||||
TestFillQuoteTransformerBridge: TestFillQuoteTransformerBridge as ContractArtifact,
|
||||
TestFillQuoteTransformerExchange: TestFillQuoteTransformerExchange as ContractArtifact,
|
||||
TestFillQuoteTransformerHost: TestFillQuoteTransformerHost as ContractArtifact,
|
||||
TestFixinProtocolFees: TestFixinProtocolFees as ContractArtifact,
|
||||
TestFullMigration: TestFullMigration as ContractArtifact,
|
||||
TestInitialMigration: TestInitialMigration as ContractArtifact,
|
||||
TestLibNativeOrder: TestLibNativeOrder as ContractArtifact,
|
||||
TestLibSignature: TestLibSignature as ContractArtifact,
|
||||
TestLibTokenSpender: TestLibTokenSpender as ContractArtifact,
|
||||
TestLiquidityProvider: TestLiquidityProvider as ContractArtifact,
|
||||
TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact,
|
||||
TestMigrator: TestMigrator as ContractArtifact,
|
||||
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
|
||||
TestMintableERC20Token: TestMintableERC20Token as ContractArtifact,
|
||||
TestProtocolFees: TestProtocolFees as ContractArtifact,
|
||||
TestNativeOrdersFeature: TestNativeOrdersFeature as ContractArtifact,
|
||||
TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact,
|
||||
TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact,
|
||||
TestStaking: TestStaking as ContractArtifact,
|
||||
|
1234
contracts/zero-ex/test/features/limit_orders_feature_test.ts
Normal file
1234
contracts/zero-ex/test/features/limit_orders_feature_test.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,25 @@
|
||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { blockchainTests, constants, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils';
|
||||
|
||||
import { IOwnableFeatureContract, IZeroExContract, LiquidityProviderFeatureContract } from '../../src/wrappers';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { abis } from '../utils/abis';
|
||||
import { fullMigrateAsync } from '../utils/migration';
|
||||
import { IERC20BridgeEvents, TestBridgeContract, TestWethContract } from '../wrappers';
|
||||
import {
|
||||
LiquidityProviderSandboxContract,
|
||||
TestBridgeContract,
|
||||
TestBridgeEvents,
|
||||
TestLiquidityProviderContract,
|
||||
TestLiquidityProviderEvents,
|
||||
TestWethContract,
|
||||
} from '../wrappers';
|
||||
|
||||
blockchainTests('LiquidityProvider feature', env => {
|
||||
let zeroEx: IZeroExContract;
|
||||
let feature: LiquidityProviderFeatureContract;
|
||||
let sandbox: LiquidityProviderSandboxContract;
|
||||
let liquidityProvider: TestLiquidityProviderContract;
|
||||
let token: DummyERC20TokenContract;
|
||||
let weth: TestWethContract;
|
||||
let owner: string;
|
||||
@@ -42,107 +51,119 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
|
||||
feature = new LiquidityProviderFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis);
|
||||
sandbox = await LiquidityProviderSandboxContract.deployFrom0xArtifactAsync(
|
||||
artifacts.LiquidityProviderSandbox,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
zeroEx.address,
|
||||
);
|
||||
const featureImpl = await LiquidityProviderFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.LiquidityProviderFeature,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
weth.address,
|
||||
sandbox.address,
|
||||
);
|
||||
await new IOwnableFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis)
|
||||
.migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner)
|
||||
.awaitTransactionSuccessAsync();
|
||||
|
||||
liquidityProvider = await TestLiquidityProviderContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestLiquidityProvider,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
token.address,
|
||||
weth.address,
|
||||
);
|
||||
});
|
||||
describe('Registry', () => {
|
||||
it('`getLiquidityProviderForMarket` reverts if address is not set', async () => {
|
||||
const [xAsset, yAsset] = [randomAddress(), randomAddress()];
|
||||
let tx = feature.getLiquidityProviderForMarket(xAsset, yAsset).awaitTransactionSuccessAsync();
|
||||
expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
|
||||
);
|
||||
tx = feature.getLiquidityProviderForMarket(yAsset, xAsset).awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(yAsset, xAsset),
|
||||
);
|
||||
});
|
||||
it('can set/get a liquidity provider address for a given market', async () => {
|
||||
const expectedAddress = randomAddress();
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, expectedAddress)
|
||||
.awaitTransactionSuccessAsync();
|
||||
let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
});
|
||||
it('can update a liquidity provider address for a given market', async () => {
|
||||
const expectedAddress = randomAddress();
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, expectedAddress)
|
||||
.awaitTransactionSuccessAsync();
|
||||
let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
});
|
||||
it('can effectively remove a liquidity provider for a market by setting the address to 0', async () => {
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, constants.NULL_ADDRESS)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const tx = feature
|
||||
.getLiquidityProviderForMarket(token.address, weth.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(token.address, weth.address),
|
||||
);
|
||||
});
|
||||
it('reverts if non-owner attempts to set an address', async () => {
|
||||
const tx = feature
|
||||
.setLiquidityProviderForMarket(randomAddress(), randomAddress(), randomAddress())
|
||||
blockchainTests.resets('Sandbox', () => {
|
||||
it('Cannot call sandbox `executeSellTokenForToken` function directly', async () => {
|
||||
const tx = sandbox
|
||||
.executeSellTokenForToken(
|
||||
liquidityProvider.address,
|
||||
token.address,
|
||||
weth.address,
|
||||
taker,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker, owner));
|
||||
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker));
|
||||
});
|
||||
it('Cannot call sandbox `executeSellEthForToken` function directly', async () => {
|
||||
const tx = sandbox
|
||||
.executeSellEthForToken(
|
||||
liquidityProvider.address,
|
||||
token.address,
|
||||
taker,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker));
|
||||
});
|
||||
it('Cannot call sandbox `executeSellTokenForEth` function directly', async () => {
|
||||
const tx = sandbox
|
||||
.executeSellTokenForEth(
|
||||
liquidityProvider.address,
|
||||
token.address,
|
||||
taker,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker));
|
||||
});
|
||||
});
|
||||
blockchainTests.resets('Swap', () => {
|
||||
let liquidityProvider: TestBridgeContract;
|
||||
const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
||||
|
||||
before(async () => {
|
||||
liquidityProvider = await TestBridgeContract.deployFrom0xArtifactAsync(
|
||||
it('Successfully executes an ERC20-ERC20 swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
token.address,
|
||||
weth.address,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
verifyEventsFromLogs(
|
||||
tx.logs,
|
||||
[
|
||||
{
|
||||
inputToken: token.address,
|
||||
outputToken: weth.address,
|
||||
recipient: taker,
|
||||
minBuyAmount: constants.ZERO_AMOUNT,
|
||||
inputTokenBalance: constants.ONE_ETHER,
|
||||
},
|
||||
],
|
||||
TestLiquidityProviderEvents.SellTokenForToken,
|
||||
);
|
||||
});
|
||||
it('Successfully executes an ERC20-ERC20 swap (backwards-compatibility)', async () => {
|
||||
const bridge = await TestBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
token.address,
|
||||
weth.address,
|
||||
token.address,
|
||||
);
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, liquidityProvider.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
it('Cannot execute a swap for a market without a liquidity provider set', async () => {
|
||||
const [xAsset, yAsset] = [randomAddress(), randomAddress()];
|
||||
const tx = feature
|
||||
.sellToLiquidityProvider(
|
||||
xAsset,
|
||||
yAsset,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
|
||||
);
|
||||
});
|
||||
it('Successfully executes an ERC20-ERC20 swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
weth.address,
|
||||
token.address,
|
||||
weth.address,
|
||||
bridge.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
verifyEventsFromLogs(
|
||||
@@ -153,22 +174,24 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
outputToken: weth.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
from: bridge.address,
|
||||
to: taker,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
TestBridgeEvents.ERC20BridgeTransfer,
|
||||
);
|
||||
});
|
||||
it('Reverts if cannot fulfill the minimum buy amount', async () => {
|
||||
const minBuyAmount = new BigNumber(1);
|
||||
const tx = feature
|
||||
.sellToLiquidityProvider(
|
||||
weth.address,
|
||||
token.address,
|
||||
weth.address,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
minBuyAmount,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(
|
||||
@@ -185,36 +208,38 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
it('Successfully executes an ETH-ERC20 swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
token.address,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
token.address,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker, value: constants.ONE_ETHER });
|
||||
verifyEventsFromLogs(
|
||||
tx.logs,
|
||||
[
|
||||
{
|
||||
inputToken: weth.address,
|
||||
outputToken: token.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
to: taker,
|
||||
recipient: taker,
|
||||
minBuyAmount: constants.ZERO_AMOUNT,
|
||||
ethBalance: constants.ONE_ETHER,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
TestLiquidityProviderEvents.SellEthForToken,
|
||||
);
|
||||
});
|
||||
it('Successfully executes an ERC20-ETH swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
ETH_TOKEN_ADDRESS,
|
||||
token.address,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
verifyEventsFromLogs(
|
||||
@@ -222,14 +247,12 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
[
|
||||
{
|
||||
inputToken: token.address,
|
||||
outputToken: weth.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
to: zeroEx.address,
|
||||
recipient: taker,
|
||||
minBuyAmount: constants.ZERO_AMOUNT,
|
||||
inputTokenBalance: constants.ONE_ETHER,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
TestLiquidityProviderEvents.SellTokenForEth,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -66,7 +66,7 @@ blockchainTests.resets('SimpleFunctionRegistry feature', env => {
|
||||
|
||||
it('`rollback()` to zero impl succeeds for unregistered function', async () => {
|
||||
await registry.rollback(testFnSelector, NULL_ADDRESS).awaitTransactionSuccessAsync();
|
||||
const impl = await zeroEx.getFunctionImplementation(testFnSelector).callAsync();
|
||||
const impl = await registry.getFunctionImplementation(testFnSelector).callAsync();
|
||||
expect(impl).to.eq(NULL_ADDRESS);
|
||||
});
|
||||
|
||||
|
@@ -10,8 +10,10 @@ import { deployFullFeaturesAsync, FullFeatures } from './utils/migration';
|
||||
import {
|
||||
AllowanceTargetContract,
|
||||
IMetaTransactionsFeatureContract,
|
||||
INativeOrdersFeatureContract,
|
||||
IOwnableFeatureContract,
|
||||
ISignatureValidatorFeatureContract,
|
||||
ISimpleFunctionRegistryFeatureContract,
|
||||
ITokenSpenderFeatureContract,
|
||||
ITransformERC20FeatureContract,
|
||||
TestFullMigrationContract,
|
||||
@@ -25,6 +27,7 @@ blockchainTests.resets('Full migration', env => {
|
||||
let zeroEx: ZeroExContract;
|
||||
let features: FullFeatures;
|
||||
let migrator: TestFullMigrationContract;
|
||||
let registry: ISimpleFunctionRegistryFeatureContract;
|
||||
const transformerDeployer = randomAddress();
|
||||
|
||||
before(async () => {
|
||||
@@ -43,10 +46,11 @@ blockchainTests.resets('Full migration', env => {
|
||||
artifacts,
|
||||
await migrator.getBootstrapper().callAsync(),
|
||||
);
|
||||
features = await deployFullFeaturesAsync(env.provider, env.txDefaults, zeroEx.address);
|
||||
features = await deployFullFeaturesAsync(env.provider, env.txDefaults, { zeroExAddress: zeroEx.address });
|
||||
await migrator
|
||||
.initializeZeroEx(owner, zeroEx.address, features, { transformerDeployer })
|
||||
.migrateZeroEx(owner, zeroEx.address, features, { transformerDeployer })
|
||||
.awaitTransactionSuccessAsync();
|
||||
registry = new ISimpleFunctionRegistryFeatureContract(zeroEx.address, env.provider, env.txDefaults);
|
||||
});
|
||||
|
||||
it('ZeroEx has the correct owner', async () => {
|
||||
@@ -60,10 +64,10 @@ blockchainTests.resets('Full migration', env => {
|
||||
expect(dieRecipient).to.eq(owner);
|
||||
});
|
||||
|
||||
it('Non-deployer cannot call initializeZeroEx()', async () => {
|
||||
it('Non-deployer cannot call migrateZeroEx()', async () => {
|
||||
const notDeployer = randomAddress();
|
||||
const tx = migrator
|
||||
.initializeZeroEx(owner, zeroEx.address, features, { transformerDeployer })
|
||||
.migrateZeroEx(owner, zeroEx.address, features, { transformerDeployer })
|
||||
.callAsync({ from: notDeployer });
|
||||
return expect(tx).to.revertWith('FullMigration/INVALID_SENDER');
|
||||
});
|
||||
@@ -100,6 +104,31 @@ blockchainTests.resets('Full migration', env => {
|
||||
'getMetaTransactionHash',
|
||||
],
|
||||
},
|
||||
LimitOrdersFeature: {
|
||||
contractType: INativeOrdersFeatureContract,
|
||||
fns: [
|
||||
'transferProtocolFeesForPools',
|
||||
'fillLimitOrder',
|
||||
'fillRfqOrder',
|
||||
'fillOrKillLimitOrder',
|
||||
'fillOrKillRfqOrder',
|
||||
'_fillLimitOrder',
|
||||
'_fillRfqOrder',
|
||||
'cancelLimitOrder',
|
||||
'cancelRfqOrder',
|
||||
'batchCancelLimitOrders',
|
||||
'batchCancelRfqOrders',
|
||||
'cancelPairLimitOrders',
|
||||
'batchCancelPairLimitOrders',
|
||||
'cancelPairRfqOrders',
|
||||
'batchCancelPairRfqOrders',
|
||||
'getLimitOrderInfo',
|
||||
'getRfqOrderInfo',
|
||||
'getLimitOrderHash',
|
||||
'getRfqOrderHash',
|
||||
'getProtocolFeeMultiplier',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
function createFakeInputs(inputs: DataItem[] | DataItem): any | any[] {
|
||||
@@ -136,6 +165,11 @@ blockchainTests.resets('Full migration', env => {
|
||||
return hexUtils.random(parseInt(/\d+$/.exec(item.type)![0], 10));
|
||||
}
|
||||
if (/^uint\d+$/.test(item.type)) {
|
||||
if (item.type === 'uint8') {
|
||||
// Solidity will revert if enum values are out of range, so
|
||||
// play it safe and pick zero.
|
||||
return 0;
|
||||
}
|
||||
return new BigNumber(hexUtils.random(parseInt(/\d+$/.exec(item.type)![0], 10) / 8));
|
||||
}
|
||||
if (/^int\d+$/.test(item.type)) {
|
||||
@@ -157,7 +191,7 @@ blockchainTests.resets('Full migration', env => {
|
||||
for (const fn of featureInfo.fns) {
|
||||
it(`${fn} is registered`, async () => {
|
||||
const selector = contract.getSelector(fn);
|
||||
const impl = await zeroEx.getFunctionImplementation(selector).callAsync();
|
||||
const impl = await registry.getFunctionImplementation(selector).callAsync();
|
||||
expect(impl).to.not.eq(NULL_ADDRESS);
|
||||
});
|
||||
|
||||
|
34
contracts/zero-ex/test/lib_limit_orders_test.ts
Normal file
34
contracts/zero-ex/test/lib_limit_orders_test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { blockchainTests, describe, expect } from '@0x/contracts-test-utils';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { getRandomLimitOrder, getRandomRfqOrder } from './utils/orders';
|
||||
import { TestLibNativeOrderContract } from './wrappers';
|
||||
|
||||
blockchainTests('LibLimitOrder tests', env => {
|
||||
let testContract: TestLibNativeOrderContract;
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestLibNativeOrderContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestLibNativeOrder,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('getLimitOrderStructHash()', () => {
|
||||
it('returns the correct hash', async () => {
|
||||
const order = getRandomLimitOrder();
|
||||
const structHash = await testContract.getLimitOrderStructHash(order).callAsync();
|
||||
expect(structHash).to.eq(order.getStructHash());
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRfqOrderStructHash()', () => {
|
||||
it('returns the correct hash', async () => {
|
||||
const order = getRandomRfqOrder();
|
||||
const structHash = await testContract.getRfqOrderStructHash(order).callAsync();
|
||||
expect(structHash).to.eq(order.getStructHash());
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,23 +1,20 @@
|
||||
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { AuthorizableRevertErrors, BigNumber, hexUtils } from '@0x/utils';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestProtocolFeesContract, TestStakingContract, TestWethContract } from './wrappers';
|
||||
import { FeeCollectorContract, TestFixinProtocolFeesContract, TestStakingContract, TestWethContract } from './wrappers';
|
||||
|
||||
blockchainTests.resets('ProtocolFees', env => {
|
||||
let payer: string;
|
||||
let protocolFees: TestProtocolFeesContract;
|
||||
const FEE_MULTIPLIER = 70e3;
|
||||
let taker: string;
|
||||
let unauthorized: string;
|
||||
let protocolFees: TestFixinProtocolFeesContract;
|
||||
let staking: TestStakingContract;
|
||||
let weth: TestWethContract;
|
||||
let singleFeeAmount: BigNumber;
|
||||
|
||||
before(async () => {
|
||||
[payer] = await env.getAccountAddressesAsync();
|
||||
protocolFees = await TestProtocolFeesContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestProtocolFees,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
[taker, unauthorized] = await env.getAccountAddressesAsync();
|
||||
weth = await TestWethContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestWeth,
|
||||
env.provider,
|
||||
@@ -31,45 +28,107 @@ blockchainTests.resets('ProtocolFees', env => {
|
||||
artifacts,
|
||||
weth.address,
|
||||
);
|
||||
await weth.mint(payer, constants.ONE_ETHER).awaitTransactionSuccessAsync();
|
||||
await weth.approve(protocolFees.address, constants.ONE_ETHER).awaitTransactionSuccessAsync({ from: payer });
|
||||
protocolFees = await TestFixinProtocolFeesContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestFixinProtocolFees,
|
||||
env.provider,
|
||||
{ ...env.txDefaults, from: taker },
|
||||
artifacts,
|
||||
weth.address,
|
||||
staking.address,
|
||||
FEE_MULTIPLIER,
|
||||
);
|
||||
singleFeeAmount = await protocolFees.getSingleProtocolFee().callAsync();
|
||||
await weth.mint(taker, singleFeeAmount).awaitTransactionSuccessAsync();
|
||||
await weth.approve(protocolFees.address, singleFeeAmount).awaitTransactionSuccessAsync({ from: taker });
|
||||
});
|
||||
|
||||
describe('FeeCollector', () => {
|
||||
it('should disallow unauthorized initialization', async () => {
|
||||
const pool = hexUtils.random();
|
||||
|
||||
await protocolFees.collectProtocolFee(pool).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
||||
await protocolFees.transferFeesForPool(pool).awaitTransactionSuccessAsync();
|
||||
|
||||
const feeCollector = new FeeCollectorContract(
|
||||
await protocolFees.getFeeCollector(pool).callAsync(),
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
);
|
||||
|
||||
const tx = feeCollector
|
||||
.initialize(weth.address, staking.address, pool)
|
||||
.sendTransactionAsync({ from: unauthorized });
|
||||
return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(unauthorized));
|
||||
});
|
||||
});
|
||||
|
||||
describe('_collectProtocolFee()', () => {
|
||||
it('can collect a protocol fee multiple times', async () => {
|
||||
const poolId = hexUtils.random();
|
||||
const amount1 = new BigNumber(123456);
|
||||
const amount2 = new BigNumber(456789);
|
||||
const pool1 = hexUtils.random();
|
||||
const pool2 = hexUtils.random();
|
||||
let feeCollector1Address: string;
|
||||
let feeCollector2Address: string;
|
||||
|
||||
// Transfer amount1 via WETH.
|
||||
await protocolFees
|
||||
.collectProtocolFee(poolId, amount1, weth.address)
|
||||
.awaitTransactionSuccessAsync({ from: payer });
|
||||
before(async () => {
|
||||
feeCollector1Address = await protocolFees.getFeeCollector(pool1).callAsync();
|
||||
feeCollector2Address = await protocolFees.getFeeCollector(pool2).callAsync();
|
||||
});
|
||||
|
||||
// Send to staking contract.
|
||||
await protocolFees
|
||||
.transferFeesForPool(poolId, staking.address, weth.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
it('should revert if insufficient ETH transferred', async () => {
|
||||
const tooLittle = singleFeeAmount.minus(1);
|
||||
const tx = protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: tooLittle });
|
||||
return expect(tx).to.revertWith('FixinProtocolFees/ETHER_TRANSFER_FALIED');
|
||||
});
|
||||
|
||||
// Transfer amount2 via ETH.
|
||||
await protocolFees
|
||||
.collectProtocolFee(poolId, amount2, weth.address)
|
||||
.awaitTransactionSuccessAsync({ from: payer, value: amount2 });
|
||||
it('should accept ETH fee', async () => {
|
||||
const beforeETH = await env.web3Wrapper.getBalanceInWeiAsync(taker);
|
||||
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
||||
const afterETH = await env.web3Wrapper.getBalanceInWeiAsync(taker);
|
||||
|
||||
// Send to staking contract again.
|
||||
await protocolFees
|
||||
.transferFeesForPool(poolId, staking.address, weth.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
// We check for greater than fee spent to allow for spending on gas.
|
||||
await expect(beforeETH.minus(afterETH)).to.bignumber.gt(singleFeeAmount);
|
||||
|
||||
const balance = await staking.balanceForPool(poolId).callAsync();
|
||||
const wethBalance = await weth.balanceOf(staking.address).callAsync();
|
||||
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector1Address)).to.bignumber.eq(
|
||||
singleFeeAmount,
|
||||
);
|
||||
});
|
||||
|
||||
// Check that staking accounted for the collected ether properly.
|
||||
expect(balance).to.bignumber.eq(wethBalance);
|
||||
it('should accept ETH after first transfer', async () => {
|
||||
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
||||
await protocolFees.transferFeesForPool(pool1).awaitTransactionSuccessAsync();
|
||||
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
||||
await protocolFees.transferFeesForPool(pool1).awaitTransactionSuccessAsync();
|
||||
|
||||
// We leave 1 wei behind, of both ETH and WETH, for gas reasons.
|
||||
const total = amount1.plus(amount2).minus(2);
|
||||
return expect(balance).to.bignumber.eq(total);
|
||||
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
|
||||
|
||||
// We leave 1 wei of WETH behind.
|
||||
await expect(balanceWETH).to.bignumber.eq(singleFeeAmount.times(2).minus(1));
|
||||
await expect(await weth.balanceOf(feeCollector1Address).callAsync()).to.bignumber.equal(1);
|
||||
// And no ETH.
|
||||
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector1Address)).to.bignumber.eq(0);
|
||||
});
|
||||
|
||||
it('should attribute fees correctly', async () => {
|
||||
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
||||
await protocolFees.transferFeesForPool(pool1).awaitTransactionSuccessAsync();
|
||||
await protocolFees.collectProtocolFee(pool2).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
||||
await protocolFees.transferFeesForPool(pool2).awaitTransactionSuccessAsync();
|
||||
|
||||
const pool1Balance = await staking.balanceForPool(pool1).callAsync();
|
||||
const pool2Balance = await staking.balanceForPool(pool2).callAsync();
|
||||
|
||||
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
|
||||
|
||||
await expect(balanceWETH).to.bignumber.equal(singleFeeAmount.times(2).minus(2));
|
||||
|
||||
// We leave 1 wei of WETH behind.
|
||||
await expect(pool1Balance).to.bignumber.equal(singleFeeAmount.minus(1));
|
||||
await expect(pool2Balance).to.bignumber.equal(singleFeeAmount.minus(1));
|
||||
await expect(await weth.balanceOf(feeCollector1Address).callAsync()).to.bignumber.equal(1);
|
||||
await expect(await weth.balanceOf(feeCollector2Address).callAsync()).to.bignumber.equal(1);
|
||||
await expect(pool2Balance).to.bignumber.equal(singleFeeAmount.minus(1));
|
||||
// And no ETH.
|
||||
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector1Address)).to.bignumber.eq(0);
|
||||
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector2Address)).to.bignumber.eq(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -4,6 +4,7 @@ export {
|
||||
deployFullFeaturesAsync,
|
||||
initialMigrateAsync,
|
||||
fullMigrateAsync,
|
||||
FullMigrationOpts,
|
||||
FullMigrationConfig,
|
||||
FullFeaturesDeployConfig,
|
||||
FullFeatures,
|
||||
} from '../../src/migration';
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user