Compare commits

..

12 Commits

Author SHA1 Message Date
Github Actions
d2018f07a2 Publish
- @0x/contracts-asset-proxy@3.6.5
 - @0x/contracts-broker@1.1.13
 - @0x/contracts-coordinator@3.1.14
 - @0x/contracts-dev-utils@1.3.12
 - @0x/contracts-erc1155@2.1.14
 - @0x/contracts-erc20@3.2.8
 - @0x/contracts-erc721@3.1.14
 - @0x/contracts-exchange-forwarder@4.2.14
 - @0x/contracts-exchange-libs@4.3.14
 - @0x/contracts-exchange@3.2.14
 - @0x/contracts-extensions@6.2.8
 - @0x/contracts-integrations@2.7.8
 - @0x/contracts-multisig@4.1.14
 - @0x/contracts-staking@2.0.21
 - @0x/contracts-test-utils@5.3.11
 - @0x/contracts-utils@4.5.8
 - @0x/contracts-zero-ex@0.9.0
 - @0x/asset-swapper@5.1.0
 - @0x/contract-addresses@5.3.0
 - @0x/contract-artifacts@3.9.0
 - @0x/contract-wrappers-test@12.2.24
 - @0x/contract-wrappers@13.10.0
 - @0x/migrations@6.5.0
 - @0x/order-utils@10.4.6
2020-11-13 21:14:01 +00:00
Github Actions
d2e57d8163 Updated CHANGELOGS & MD docs 2020-11-13 21:13:51 +00:00
mzhu25
7403c0255a Feature/liquidity provider sandbox (#16)
* Update liquidity provider feature to use sandbox

* add support for liquidity provider feature in the exchange proxy swap quote consumer

* Move to off-chain liquidity provider registry

* Update ILiquidityProvider interface

* Remove some unused artifacts and wrappers

* Consolidate ILiquidityProvider

* prettier

* lint

* Address PR feedback

* Add failover to sandbox

* Add test for failover behavior in LiquidityProviderSandbox

* Update changelogs

* Emit events for the new LiquidityProvider scenarios

* Fix swap quote consumer bug

* post-rebase fixes

* `@0x/contracts-zero-ex`: bump feature versions

* Add default field to TokenAdjacencyGraph

* update addresses

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-11-13 12:22:21 -08:00
Steve Marx
75dcd687e2 better protocol fee tests (#25)
* better protocol fee tests
2020-11-09 12:44:52 -05:00
Steve Marx
afd4805421 rewrite ZeroEx in Yul (#23)
rewrite ZeroEx in Yul
2020-11-06 22:03:07 -05:00
Github Actions
6aa582d140 Publish
- @0x/contracts-integrations@2.7.7
 - @0x/asset-swapper@5.0.3
2020-11-05 23:57:34 +00:00
Github Actions
534d92fa00 Updated CHANGELOGS & MD docs 2020-11-05 23:57:28 +00:00
Romain Butteaud
37aae134ab feat: adding Curve pools: PAX, hBTC, metapools: gUSD, hUSD, USDn, mUSD, tBTC (#26)
* feat: adding Curve pools: PAX, hbtc, metapools: gusd, husd, usdn, musd, tbtc

* feat: CHANGELOG

* fix: bad import

* fix: curve_y address downcase, use POOLS addresses for names

* feat: add metaToken attribute to disable metapools for non-metaTokens in Curve

* fix: CHANGELOG
2020-11-05 15:27:45 -08:00
Daniel Pyrathon
36bd8f68c9 adds amendments to the rollout feature flag. Rollout indicative quote… (#30)
* adds amendments to the rollout feature flag. Rollout indicative quotes indipendently from firm quotes.

* Updates based on Brandon's feedback
2020-11-05 12:46:06 -08:00
Github Actions
c3ad42221e Publish
- @0x/contracts-asset-proxy@3.6.4
 - @0x/contracts-broker@1.1.12
 - @0x/contracts-coordinator@3.1.13
 - @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-forwarder@4.2.13
 - @0x/contracts-exchange-libs@4.3.13
 - @0x/contracts-exchange@3.2.13
 - @0x/contracts-extensions@6.2.7
 - @0x/contracts-integrations@2.7.6
 - @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-zero-ex@0.8.0
 - @0x/asset-swapper@5.0.2
 - @0x/contract-addresses@5.2.0
 - @0x/contract-wrappers-test@12.2.23
 - @0x/contract-wrappers@13.9.5
 - @0x/migrations@6.4.7
 - @0x/order-utils@10.4.5
2020-11-03 06:46:11 +00:00
Github Actions
602ac1f626 Updated CHANGELOGS & MD docs 2020-11-03 06:46:05 +00:00
Lawrence Forman
3126795efe @0x/contract-addresses: deploy FQT with CORRECT address (#29)
`@0x/contracts-zero-ex`: Trust `boughtAmount` returned by LP

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-11-03 01:12:57 -05:00
140 changed files with 2233 additions and 2422 deletions

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "3.6.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "3.6.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "3.6.3",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.6.5 - _November 13, 2020_
* Dependencies updated
## v3.6.4 - _November 3, 2020_
* Dependencies updated
## v3.6.3 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-asset-proxy",
"version": "3.6.3",
"version": "3.6.5",
"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.4",
"@0x/contract-wrappers": "^13.10.0",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@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.12",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-erc721": "^3.1.12",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/order-utils": "^10.4.4",
"@0x/contracts-erc1155": "^2.1.14",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-erc721": "^3.1.14",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/order-utils": "^10.4.6",
"@0x/types": "^3.3.0",
"@0x/typescript-typings": "^5.1.5",
"@0x/utils": "^6.1.0",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "1.1.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "1.1.12",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "1.1.11",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.1.13 - _November 13, 2020_
* Dependencies updated
## v1.1.12 - _November 3, 2020_
* Dependencies updated
## v1.1.11 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-broker",
"version": "1.1.11",
"version": "1.1.13",
"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.3",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-erc721": "^3.1.12",
"@0x/contracts-exchange": "^3.2.12",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-erc721": "^3.1.14",
"@0x/contracts-exchange": "^3.2.14",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@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.4",
"@0x/order-utils": "^10.4.6",
"@0x/typescript-typings": "^5.1.5",
"@0x/utils": "^6.1.0",
"ethereum-types": "^3.3.3"

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "3.1.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "3.1.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "3.1.12",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.14 - _November 13, 2020_
* Dependencies updated
## v3.1.13 - _November 3, 2020_
* Dependencies updated
## v3.1.12 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-coordinator",
"version": "3.1.12",
"version": "3.1.14",
"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.3",
"@0x/contracts-dev-utils": "^1.3.10",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-dev-utils": "^1.3.12",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-gen": "2.0.18",
"@0x/dev-utils": "^4.0.1",
"@0x/order-utils": "^10.4.4",
"@0x/order-utils": "^10.4.6",
"@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.1.0",
"@0x/contracts-exchange": "^3.2.12",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contract-addresses": "^5.3.0",
"@0x/contracts-exchange": "^3.2.14",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@0x/json-schemas": "^5.3.3",
"@0x/types": "^3.3.0",
"@0x/typescript-typings": "^5.1.5",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "1.3.12",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "1.3.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "1.3.10",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.3.12 - _November 13, 2020_
* Dependencies updated
## v1.3.11 - _November 3, 2020_
* Dependencies updated
## v1.3.10 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-dev-utils",
"version": "1.3.10",
"version": "1.3.12",
"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.3",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/sol-compiler": "^4.2.7",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "2.1.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "2.1.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "2.1.12",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.1.14 - _November 13, 2020_
* Dependencies updated
## v2.1.13 - _November 3, 2020_
* Dependencies updated
## v2.1.12 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc1155",
"version": "2.1.12",
"version": "2.1.14",
"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.6",
"@0x/contracts-utils": "^4.5.8",
"@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.9",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/utils": "^6.1.0",
"@0x/web3-wrapper": "^7.2.8",
"lodash": "^4.17.11"

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "3.2.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "3.2.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "3.2.6",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.8 - _November 13, 2020_
* Dependencies updated
## v3.2.7 - _November 3, 2020_
* Dependencies updated
## v3.2.6 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "3.2.6",
"version": "3.2.8",
"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.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@0x/dev-utils": "^4.0.1",
"@0x/sol-compiler": "^4.2.7",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "3.1.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "3.1.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "3.1.12",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.14 - _November 13, 2020_
* Dependencies updated
## v3.1.13 - _November 3, 2020_
* Dependencies updated
## v3.1.12 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc721",
"version": "3.1.12",
"version": "3.1.14",
"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.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@0x/dev-utils": "^4.0.1",
"@0x/sol-compiler": "^4.2.7",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "4.2.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "4.2.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "4.2.12",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.2.14 - _November 13, 2020_
* Dependencies updated
## v4.2.13 - _November 3, 2020_
* Dependencies updated
## v4.2.12 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-forwarder",
"version": "4.2.12",
"version": "4.2.14",
"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.3",
"@0x/contracts-dev-utils": "^1.3.10",
"@0x/contracts-erc1155": "^2.1.12",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-erc721": "^3.1.12",
"@0x/contracts-exchange": "^3.2.12",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-dev-utils": "^1.3.12",
"@0x/contracts-erc1155": "^2.1.14",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-erc721": "^3.1.14",
"@0x/contracts-exchange": "^3.2.14",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@0x/dev-utils": "^4.0.1",
"@0x/order-utils": "^10.4.4",
"@0x/order-utils": "^10.4.6",
"@0x/sol-compiler": "^4.2.7",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "4.3.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "4.3.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "4.3.12",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.3.14 - _November 13, 2020_
* Dependencies updated
## v4.3.13 - _November 3, 2020_
* Dependencies updated
## v4.3.12 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-libs",
"version": "4.3.12",
"version": "4.3.14",
"engines": {
"node": ">=6.12"
},
@@ -81,9 +81,9 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.11",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/order-utils": "^10.4.4",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@0x/order-utils": "^10.4.6",
"@0x/types": "^3.3.0",
"@0x/typescript-typings": "^5.1.5",
"@0x/utils": "^6.1.0",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "3.2.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "3.2.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "3.2.12",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.14 - _November 13, 2020_
* Dependencies updated
## v3.2.13 - _November 3, 2020_
* Dependencies updated
## v3.2.12 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange",
"version": "3.2.12",
"version": "3.2.14",
"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.3",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-multisig": "^4.1.12",
"@0x/contracts-staking": "^2.0.19",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-multisig": "^4.1.14",
"@0x/contracts-staking": "^2.0.21",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@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.10",
"@0x/contracts-erc1155": "^2.1.12",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-erc721": "^3.1.12",
"@0x/order-utils": "^10.4.4",
"@0x/contracts-dev-utils": "^1.3.12",
"@0x/contracts-erc1155": "^2.1.14",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-erc721": "^3.1.14",
"@0x/order-utils": "^10.4.6",
"@0x/utils": "^6.1.0",
"lodash": "^4.17.11"
},

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "6.2.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "6.2.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "6.2.6",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v6.2.8 - _November 13, 2020_
* Dependencies updated
## v6.2.7 - _November 3, 2020_
* Dependencies updated
## v6.2.6 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-extensions",
"version": "6.2.6",
"version": "6.2.8",
"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.3",
"@0x/contracts-dev-utils": "^1.3.10",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-erc721": "^3.1.12",
"@0x/contracts-exchange": "^3.2.12",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-dev-utils": "^1.3.12",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-erc721": "^3.1.14",
"@0x/contracts-exchange": "^3.2.14",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-utils": "^4.5.8",
"@0x/dev-utils": "^4.0.1",
"@0x/order-utils": "^10.4.4",
"@0x/order-utils": "^10.4.6",
"@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.9",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/typescript-typings": "^5.1.5",
"ethereum-types": "^3.3.3"
},

View File

@@ -1,4 +1,31 @@
[
{
"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",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "2.7.5",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.7.8 - _November 13, 2020_
* Dependencies updated
## v2.7.7 - _November 5, 2020_
* Dependencies updated
## v2.7.6 - _November 3, 2020_
* Dependencies updated
## v2.7.5 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-integrations",
"version": "2.7.5",
"version": "2.7.8",
"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.1.0",
"@0x/contract-wrappers": "^13.9.4",
"@0x/contracts-broker": "^1.1.11",
"@0x/contracts-coordinator": "^3.1.12",
"@0x/contracts-dev-utils": "^1.3.10",
"@0x/contracts-exchange-forwarder": "^4.2.12",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/contracts-extensions": "^6.2.6",
"@0x/contract-addresses": "^5.3.0",
"@0x/contract-wrappers": "^13.10.0",
"@0x/contracts-broker": "^1.1.13",
"@0x/contracts-coordinator": "^3.1.14",
"@0x/contracts-dev-utils": "^1.3.12",
"@0x/contracts-exchange-forwarder": "^4.2.14",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/contracts-extensions": "^6.2.8",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-utils": "^4.5.8",
"@0x/coordinator-server": "^1.0.5",
"@0x/dev-utils": "^4.0.1",
"@0x/migrations": "^6.4.6",
"@0x/order-utils": "^10.4.4",
"@0x/migrations": "^6.5.0",
"@0x/order-utils": "^10.4.6",
"@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.1",
"@0x/asset-swapper": "^5.1.0",
"@0x/base-contract": "^6.2.11",
"@0x/contracts-asset-proxy": "^3.6.3",
"@0x/contracts-erc1155": "^2.1.12",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-erc721": "^3.1.12",
"@0x/contracts-exchange": "^3.2.12",
"@0x/contracts-multisig": "^4.1.12",
"@0x/contracts-staking": "^2.0.19",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-zero-ex": "^0.7.0",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-erc1155": "^2.1.14",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-erc721": "^3.1.14",
"@0x/contracts-exchange": "^3.2.14",
"@0x/contracts-multisig": "^4.1.14",
"@0x/contracts-staking": "^2.0.21",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-zero-ex": "^0.9.0",
"@0x/subproviders": "^6.1.9",
"@0x/types": "^3.3.0",
"@0x/typescript-typings": "^5.1.5",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "4.1.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "4.1.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "4.1.12",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.1.14 - _November 13, 2020_
* Dependencies updated
## v4.1.13 - _November 3, 2020_
* Dependencies updated
## v4.1.12 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-multisig",
"version": "4.1.12",
"version": "4.1.14",
"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.3",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@0x/dev-utils": "^4.0.1",
"@0x/sol-compiler": "^4.2.7",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "2.0.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "2.0.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "2.0.19",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.21 - _November 13, 2020_
* Dependencies updated
## v2.0.20 - _November 3, 2020_
* Dependencies updated
## v2.0.19 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-staking",
"version": "2.0.19",
"version": "2.0.21",
"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.3",
"@0x/contracts-dev-utils": "^1.3.10",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-dev-utils": "^1.3.12",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-utils": "^4.5.8",
"@0x/dev-utils": "^4.0.1",
"@0x/order-utils": "^10.4.4",
"@0x/order-utils": "^10.4.6",
"@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.9",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/typescript-typings": "^5.1.5",
"@0x/utils": "^6.1.0",
"ethereum-types": "^3.3.3",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "5.3.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "5.3.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "5.3.9",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.3.11 - _November 13, 2020_
* Dependencies updated
## v5.3.10 - _November 3, 2020_
* Dependencies updated
## v5.3.9 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-test-utils",
"version": "5.3.9",
"version": "5.3.11",
"engines": {
"node": ">=6.12"
},
@@ -44,10 +44,10 @@
"dependencies": {
"@0x/assert": "^3.0.17",
"@0x/base-contract": "^6.2.11",
"@0x/contract-addresses": "^5.1.0",
"@0x/contract-addresses": "^5.3.0",
"@0x/dev-utils": "^4.0.1",
"@0x/json-schemas": "^5.3.3",
"@0x/order-utils": "^10.4.4",
"@0x/order-utils": "^10.4.6",
"@0x/sol-coverage": "^4.0.18",
"@0x/sol-profiler": "^4.1.8",
"@0x/sol-trace": "^3.0.18",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1605302002,
"version": "4.5.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "4.5.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "4.5.6",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.5.8 - _November 13, 2020_
* Dependencies updated
## v4.5.7 - _November 3, 2020_
* Dependencies updated
## v4.5.6 - _November 3, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-utils",
"version": "4.5.6",
"version": "4.5.8",
"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.9",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/dev-utils": "^4.0.1",
"@0x/order-utils": "^10.4.4",
"@0x/order-utils": "^10.4.6",
"@0x/sol-compiler": "^4.2.7",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.0",

View File

@@ -1,4 +1,36 @@
[
{
"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": [
{
"note": "Trust LP boughtAmount return value",
"pr": 29
}
],
"timestamp": 1604385937
},
{
"version": "0.7.0",
"changes": [

View File

@@ -5,6 +5,17 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## 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)
## v0.7.0 - _November 3, 2020_
* Change `ProtocolFeeUnfunded` event in FQT (#28)

View File

@@ -44,14 +44,4 @@ interface IZeroEx is
/// @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);
}

View File

@@ -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)
}
(bool success, bytes memory resultData) = impl.delegatecall(msg.data);
if (!success) {
_revertWithData(resultData);
}
_returnWithData(resultData);
// 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)
}
/// @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];
let success := delegatecall(
gas(),
delegate,
0x40, cdlen,
0, 0
)
let rdlen := returndatasize()
returndatacopy(0, 0, rdlen)
if success {
return(0, rdlen)
}
/// @dev Revert with arbitrary bytes.
/// @param data Revert data.
function _revertWithData(bytes memory data) private pure {
assembly { revert(add(data, 32), mload(data)) }
revert(0, rdlen)
}
/// @dev Return with arbitrary bytes.
/// @param data Return data.
function _returnWithData(bytes memory data) private pure {
assembly { return(add(data, 32), mload(data)) }
}
}

View File

@@ -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
);
}
}

View 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;
}

View 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
);
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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,7 +37,6 @@ contract LiquidityProviderFeature is
ILiquidityProviderFeature,
FixinCommon
{
using LibERC20TokenV06 for IERC20TokenV06;
using LibSafeMathV06 for uint256;
using LibRichErrorsV06 for bytes;
@@ -50,16 +47,24 @@ contract LiquidityProviderFeature is
/// @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(address zeroEx)
public
FixinCommon()
{
weth = weth_;
sandbox = new LiquidityProviderSandbox(zeroEx);
}
/// @dev Initialize and register this feature.
@@ -70,131 +75,102 @@ 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,
provider,
sellAmount
);
}
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();
}
}
}

View File

@@ -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.

View File

@@ -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, 0);
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.

View File

@@ -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.

View File

@@ -1,45 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for `LiquidityProviderFeature`.
library LibLiquidityProviderStorage {
/// @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;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.getStorageSlot(
LibStorage.StorageId.LiquidityProvider
);
// Dip into assembly to change the slot pointed to by the local
// variable `stor`.
// See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries
assembly { stor_slot := storageSlot }
}
}

View File

@@ -36,8 +36,7 @@ library LibStorage {
TokenSpender,
TransformERC20,
MetaTransactions,
ReentrancyGuard,
LiquidityProvider
ReentrancyGuard
}
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced

View File

@@ -56,7 +56,6 @@ contract MixinZeroExBridge {
internal
returns (uint256 boughtAmount)
{
uint256 balanceBefore = buyToken.balanceOf(address(this));
// Trade the good old fashioned way
sellToken.compatTransfer(
bridgeAddress,
@@ -68,8 +67,8 @@ contract MixinZeroExBridge {
address(this), // recipient
1, // minBuyAmount
bridgeData
) {
boughtAmount = buyToken.balanceOf(address(this)).safeSub(balanceBefore);
) returns (uint256 _boughtAmount) {
boughtAmount = _boughtAmount;
emit ERC20BridgeTransfer(
sellToken,
buyToken,
@@ -79,6 +78,7 @@ contract MixinZeroExBridge {
address(this)
);
} catch {
uint256 balanceBefore = buyToken.balanceOf(address(this));
IERC20Bridge(bridgeAddress).bridgeTransferFrom(
address(buyToken),
bridgeAddress,

View File

@@ -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;

View File

@@ -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(
FillBehavior memory behavior = abi.decode(auxiliaryData, (FillBehavior));
boughtAmount = LibMathV06.getPartialAmountFloor(
behavior.makerAssetMintRatio,
1e18,
behavior.amount
)
);
return ERC20_BRIDGE_PROXY_ID;
TestMintableERC20Token(makerToken).mint(
recipient,
boughtAmount
);
}
function encodeBehaviorData(FillBehavior calldata behavior)

View File

@@ -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);
}

View 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))
);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-zero-ex",
"version": "0.7.0",
"version": "0.9.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,ILiquidityProvider",
"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|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|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|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestLibSignature|TestLibTokenSpender|TestLiquidityProvider|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"
},
"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.6",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-gen": "2.0.18",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-test-utils": "^5.3.11",
"@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.4",
"@0x/order-utils": "^10.4.6",
"@0x/subproviders": "^6.1.9",
"@0x/types": "^3.3.0",
"@0x/typescript-typings": "^5.1.5",

View File

@@ -12,6 +12,7 @@ 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 ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.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';
@@ -54,4 +55,5 @@ export const artifacts = {
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
BridgeAdapter: BridgeAdapter as ContractArtifact,
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
};

View File

@@ -10,6 +10,7 @@ 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';
export * from '../generated-wrappers/i_ownable_feature';
export * from '../generated-wrappers/i_simple_function_registry_feature';
export * from '../generated-wrappers/i_token_spender_feature';

View File

@@ -28,6 +28,7 @@ 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 InitialMigration from '../test/generated-artifacts/InitialMigration.json';
import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json';
@@ -43,7 +44,6 @@ 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';
@@ -66,6 +66,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';
@@ -95,6 +96,7 @@ import * as TestFullMigration from '../test/generated-artifacts/TestFullMigratio
import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.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';
@@ -137,6 +139,8 @@ 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,
@@ -168,7 +172,6 @@ export const artifacts = {
InitialMigration: InitialMigration as ContractArtifact,
LibBootstrap: LibBootstrap as ContractArtifact,
LibMigrate: LibMigrate as ContractArtifact,
LibLiquidityProviderStorage: LibLiquidityProviderStorage as ContractArtifact,
LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact,
LibOwnableStorage: LibOwnableStorage as ContractArtifact,
LibProxyStorage: LibProxyStorage as ContractArtifact,
@@ -217,6 +220,7 @@ export const artifacts = {
TestInitialMigration: TestInitialMigration 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,

View File

@@ -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;
@@ -47,102 +56,112 @@ blockchainTests('LiquidityProvider feature', env => {
env.provider,
env.txDefaults,
artifacts,
weth.address,
zeroEx.address,
);
sandbox = new LiquidityProviderSandboxContract(
await featureImpl.sandbox().callAsync(),
env.provider,
env.txDefaults,
);
await new IOwnableFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis)
.migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner)
.awaitTransactionSuccessAsync();
});
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())
.awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker, owner));
});
});
blockchainTests.resets('Swap', () => {
let liquidityProvider: TestBridgeContract;
const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
before(async () => {
liquidityProvider = await TestBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestBridge,
liquidityProvider = await TestLiquidityProviderContract.deployFrom0xArtifactAsync(
artifacts.TestLiquidityProvider,
env.provider,
env.txDefaults,
artifacts,
token.address,
weth.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,
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 ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
);
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', () => {
const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
it('Successfully executes an ERC20-ERC20 swap', async () => {
const tx = await feature
.sellToLiquidityProvider(
weth.address,
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,
weth.address,
token.address,
);
const tx = await feature
.sellToLiquidityProvider(
token.address,
weth.address,
bridge.address,
constants.NULL_ADDRESS,
constants.ONE_ETHER,
constants.ZERO_AMOUNT,
constants.NULL_BYTES,
)
.awaitTransactionSuccessAsync({ from: taker });
verifyEventsFromLogs(
@@ -153,22 +172,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 +206,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 +245,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,
);
});
});

View File

@@ -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);
});

View File

@@ -12,6 +12,7 @@ import {
IMetaTransactionsFeatureContract,
IOwnableFeatureContract,
ISignatureValidatorFeatureContract,
ISimpleFunctionRegistryFeatureContract,
ITokenSpenderFeatureContract,
ITransformERC20FeatureContract,
TestFullMigrationContract,
@@ -25,6 +26,7 @@ blockchainTests.resets('Full migration', env => {
let zeroEx: ZeroExContract;
let features: FullFeatures;
let migrator: TestFullMigrationContract;
let registry: ISimpleFunctionRegistryFeatureContract;
const transformerDeployer = randomAddress();
before(async () => {
@@ -47,6 +49,7 @@ blockchainTests.resets('Full migration', env => {
await migrator
.initializeZeroEx(owner, zeroEx.address, features, { transformerDeployer })
.awaitTransactionSuccessAsync();
registry = new ISimpleFunctionRegistryFeatureContract(zeroEx.address, env.provider, env.txDefaults);
});
it('ZeroEx has the correct owner', async () => {
@@ -157,7 +160,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);
});

View File

@@ -1,17 +1,19 @@
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
import { BigNumber, hexUtils } from '@0x/utils';
import { AuthorizableRevertErrors, BigNumber, hexUtils, ZeroExRevertErrors } from '@0x/utils';
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import { artifacts } from './artifacts';
import { TestProtocolFeesContract, TestStakingContract, TestWethContract } from './wrappers';
import { FeeCollectorContract, TestProtocolFeesContract, TestStakingContract, TestWethContract } from './wrappers';
blockchainTests.resets('ProtocolFees', env => {
let payer: string;
let unauthorized: string;
let protocolFees: TestProtocolFeesContract;
let staking: TestStakingContract;
let weth: TestWethContract;
before(async () => {
[payer] = await env.getAccountAddressesAsync();
[payer, unauthorized] = await env.getAccountAddressesAsync();
protocolFees = await TestProtocolFeesContract.deployFrom0xArtifactAsync(
artifacts.TestProtocolFees,
env.provider,
@@ -35,41 +37,128 @@ blockchainTests.resets('ProtocolFees', env => {
await weth.approve(protocolFees.address, constants.ONE_ETHER).awaitTransactionSuccessAsync({ from: payer });
});
async function collectAsync(
poolId: string,
amount: BigNumber,
etherValue: BigNumber,
): Promise<TransactionReceiptWithDecodedLogs> {
return protocolFees
.collectProtocolFee(poolId, amount, weth.address)
.awaitTransactionSuccessAsync({ from: payer, value: etherValue });
}
async function transferFeesAsync(poolId: string): Promise<TransactionReceiptWithDecodedLogs> {
return protocolFees.transferFeesForPool(poolId, staking.address, weth.address).awaitTransactionSuccessAsync();
}
describe('FeeCollector', () => {
it('should disallow unauthorized initialization', async () => {
const pool = hexUtils.random();
await collectAsync(pool, constants.ONE_ETHER, constants.ZERO_AMOUNT);
await transferFeesAsync(pool);
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();
// Transfer amount1 via WETH.
await protocolFees
.collectProtocolFee(poolId, amount1, weth.address)
.awaitTransactionSuccessAsync({ from: payer });
it('should revert if WETH transfer fails', async () => {
const tooMuch = constants.ONE_ETHER.plus(1);
const tx = collectAsync(pool1, constants.ONE_ETHER.plus(1), constants.ZERO_AMOUNT);
return expect(tx).to.revertWith(
new ZeroExRevertErrors.Spender.SpenderERC20TransferFromFailedError(
weth.address,
payer,
undefined,
tooMuch,
undefined,
),
);
});
// Send to staking contract.
await protocolFees
.transferFeesForPool(poolId, staking.address, weth.address)
.awaitTransactionSuccessAsync();
it('should revert if insufficient ETH transferred', async () => {
const tooLittle = constants.ONE_ETHER.minus(1);
const tx = collectAsync(pool1, constants.ONE_ETHER, 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 WETH fee', async () => {
const beforeWETH = await weth.balanceOf(payer).callAsync();
await collectAsync(pool1, constants.ONE_ETHER, constants.ZERO_AMOUNT);
const afterWETH = await weth.balanceOf(payer).callAsync();
// Send to staking contract again.
await protocolFees
.transferFeesForPool(poolId, staking.address, weth.address)
.awaitTransactionSuccessAsync();
return expect(beforeWETH.minus(afterWETH)).to.bignumber.eq(constants.ONE_ETHER);
});
const balance = await staking.balanceForPool(poolId).callAsync();
const wethBalance = await weth.balanceOf(staking.address).callAsync();
it('should accept ETH fee', async () => {
const beforeWETH = await weth.balanceOf(payer).callAsync();
const beforeETH = await env.web3Wrapper.getBalanceInWeiAsync(payer);
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
const afterWETH = await weth.balanceOf(payer).callAsync();
const afterETH = await env.web3Wrapper.getBalanceInWeiAsync(payer);
// Check that staking accounted for the collected ether properly.
expect(balance).to.bignumber.eq(wethBalance);
// We check for greater than 1 ether spent to allow for spending on gas.
await expect(beforeETH.minus(afterETH)).to.bignumber.gt(constants.ONE_ETHER);
return expect(beforeWETH).to.bignumber.eq(afterWETH);
});
// 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);
it('should transfer both ETH and WETH', async () => {
await collectAsync(pool1, constants.ONE_ETHER, constants.ZERO_AMOUNT);
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
await transferFeesAsync(pool1);
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
// We leave 1 wei behind of both ETH and WETH.
return expect(balanceWETH).to.bignumber.eq(constants.ONE_ETHER.times(2).minus(2));
});
it('should accept ETH after first transfer', async () => {
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
await transferFeesAsync(pool1);
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
await transferFeesAsync(pool1);
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
// We leave 1 wei behind of both ETH and WETH
return expect(balanceWETH).to.bignumber.eq(constants.ONE_ETHER.times(2).minus(2));
});
it('should attribute fees correctly', async () => {
const pool1Amount = new BigNumber(12345);
const pool2Amount = new BigNumber(45678);
await collectAsync(pool1, pool1Amount, pool1Amount); // ETH
await transferFeesAsync(pool1);
await collectAsync(pool2, pool2Amount, constants.ZERO_AMOUNT); // WETH
await transferFeesAsync(pool2);
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(pool1Balance.plus(pool2Balance));
// We leave 1 wei behind of both ETH and WETH.
await expect(pool1Balance).to.bignumber.equal(pool1Amount.minus(2));
// Here we paid in WETH, so there's just 1 wei of WETH held back.
return expect(pool2Balance).to.bignumber.equal(pool2Amount.minus(1));
});
});
});

View File

@@ -26,6 +26,7 @@ export * from '../test/generated-wrappers/i_flash_wallet';
export * from '../test/generated-wrappers/i_gas_token';
export * from '../test/generated-wrappers/i_liquidity_provider';
export * from '../test/generated-wrappers/i_liquidity_provider_feature';
export * from '../test/generated-wrappers/i_liquidity_provider_sandbox';
export * from '../test/generated-wrappers/i_meta_transactions_feature';
export * from '../test/generated-wrappers/i_ownable_feature';
export * from '../test/generated-wrappers/i_signature_validator_feature';
@@ -41,7 +42,6 @@ export * from '../test/generated-wrappers/lib_bootstrap';
export * from '../test/generated-wrappers/lib_common_rich_errors';
export * from '../test/generated-wrappers/lib_erc20_transformer';
export * from '../test/generated-wrappers/lib_liquidity_provider_rich_errors';
export * from '../test/generated-wrappers/lib_liquidity_provider_storage';
export * from '../test/generated-wrappers/lib_meta_transactions_rich_errors';
export * from '../test/generated-wrappers/lib_meta_transactions_storage';
export * from '../test/generated-wrappers/lib_migrate';
@@ -64,6 +64,7 @@ export * from '../test/generated-wrappers/lib_transform_erc20_rich_errors';
export * from '../test/generated-wrappers/lib_transform_erc20_storage';
export * from '../test/generated-wrappers/lib_wallet_rich_errors';
export * from '../test/generated-wrappers/liquidity_provider_feature';
export * from '../test/generated-wrappers/liquidity_provider_sandbox';
export * from '../test/generated-wrappers/log_metadata_transformer';
export * from '../test/generated-wrappers/meta_transactions_feature';
export * from '../test/generated-wrappers/mixin_adapter_addresses';
@@ -93,6 +94,7 @@ export * from '../test/generated-wrappers/test_full_migration';
export * from '../test/generated-wrappers/test_initial_migration';
export * from '../test/generated-wrappers/test_lib_signature';
export * from '../test/generated-wrappers/test_lib_token_spender';
export * from '../test/generated-wrappers/test_liquidity_provider';
export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20_feature';
export * from '../test/generated-wrappers/test_migrator';
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';

View File

@@ -83,7 +83,7 @@ blockchainTests.resets('ZeroEx contract', env => {
// registry.getSelector('extendSelf'),
];
const selectors = [...ownableSelectors, ...registrySelectors];
const impls = await Promise.all(selectors.map(s => zeroEx.getFunctionImplementation(s).callAsync()));
const impls = await Promise.all(selectors.map(s => registry.getFunctionImplementation(s).callAsync()));
for (let i = 0; i < impls.length; ++i) {
const selector = selectors[i];
const impl = impls[i];

View File

@@ -10,6 +10,7 @@
"generated-artifacts/IAllowanceTarget.json",
"generated-artifacts/IERC20Transformer.json",
"generated-artifacts/IFlashWallet.json",
"generated-artifacts/ILiquidityProvider.json",
"generated-artifacts/IOwnableFeature.json",
"generated-artifacts/ISimpleFunctionRegistryFeature.json",
"generated-artifacts/ITokenSpenderFeature.json",
@@ -50,6 +51,7 @@
"test/generated-artifacts/IGasToken.json",
"test/generated-artifacts/ILiquidityProvider.json",
"test/generated-artifacts/ILiquidityProviderFeature.json",
"test/generated-artifacts/ILiquidityProviderSandbox.json",
"test/generated-artifacts/IMetaTransactionsFeature.json",
"test/generated-artifacts/IOwnableFeature.json",
"test/generated-artifacts/ISignatureValidatorFeature.json",
@@ -65,7 +67,6 @@
"test/generated-artifacts/LibCommonRichErrors.json",
"test/generated-artifacts/LibERC20Transformer.json",
"test/generated-artifacts/LibLiquidityProviderRichErrors.json",
"test/generated-artifacts/LibLiquidityProviderStorage.json",
"test/generated-artifacts/LibMetaTransactionsRichErrors.json",
"test/generated-artifacts/LibMetaTransactionsStorage.json",
"test/generated-artifacts/LibMigrate.json",
@@ -88,6 +89,7 @@
"test/generated-artifacts/LibTransformERC20Storage.json",
"test/generated-artifacts/LibWalletRichErrors.json",
"test/generated-artifacts/LiquidityProviderFeature.json",
"test/generated-artifacts/LiquidityProviderSandbox.json",
"test/generated-artifacts/LogMetadataTransformer.json",
"test/generated-artifacts/MetaTransactionsFeature.json",
"test/generated-artifacts/MixinAdapterAddresses.json",
@@ -117,6 +119,7 @@
"test/generated-artifacts/TestInitialMigration.json",
"test/generated-artifacts/TestLibSignature.json",
"test/generated-artifacts/TestLibTokenSpender.json",
"test/generated-artifacts/TestLiquidityProvider.json",
"test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json",
"test/generated-artifacts/TestMigrator.json",
"test/generated-artifacts/TestMintTokenERC20Transformer.json",

View File

@@ -1,4 +1,40 @@
[
{
"version": "5.1.0",
"changes": [
{
"note": "Add support for LiquidityProvider feature in the swap quote consumer",
"pr": 16
},
{
"note": "Remove support for MultiBridge 😞",
"pr": 16
}
],
"timestamp": 1605302002
},
{
"timestamp": 1604620645,
"version": "5.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "5.0.2",
"changes": [
{
"note": "Dependencies updated"
},
{
"note": "adding Curve pools: PAX, hBTC, metapools: gUSD, hUSD, USDn, mUSD, tBTC",
"pr": 26
}
]
},
{
"timestamp": 1604376968,
"version": "5.0.1",

View File

@@ -5,6 +5,20 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.1.0 - _November 13, 2020_
* Add support for LiquidityProvider feature in the swap quote consumer (#16)
* Remove support for MultiBridge 😞 (#16)
## v5.0.3 - _November 5, 2020_
* Dependencies updated
## v5.0.2 - _November 3, 2020_
* Dependencies updated
* adding Curve pools: PAX, hBTC, metapools: gUSD, hUSD, USDn, mUSD, tBTC (#26)
## v5.0.1 - _November 3, 2020_
* Dependencies updated

View File

@@ -20,8 +20,7 @@ pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "./interfaces/ILiquidityProvider.sol";
import "./interfaces/ILiquidityProviderRegistry.sol";
import "@0x/contracts-zero-ex/contracts/src/vendor/ILiquidityProvider.sol";
import "./ApproximateBuys.sol";
import "./SamplerUtils.sol";
@@ -34,37 +33,26 @@ contract LiquidityProviderSampler is
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
/// @param registryAddress Address of the liquidity provider registry contract.
/// @param providerAddress Address of the liquidity provider.
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param takerTokenAmounts Taker token sell amount for each sample.
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromLiquidityProviderRegistry(
address registryAddress,
function sampleSellsFromLiquidityProvider(
address providerAddress,
address takerToken,
address makerToken,
uint256[] memory takerTokenAmounts
)
public
view
returns (uint256[] memory makerTokenAmounts, address providerAddress)
returns (uint256[] memory makerTokenAmounts)
{
// Initialize array of maker token amounts.
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
// Query registry for provider address.
providerAddress = _getLiquidityProviderFromRegistry(
registryAddress,
takerToken,
makerToken
);
// If provider doesn't exist, return all zeros.
if (providerAddress == address(0)) {
return (makerTokenAmounts, providerAddress);
}
for (uint256 i = 0; i < numSamples; i++) {
try
ILiquidityProvider(providerAddress).getSellQuote
@@ -81,68 +69,33 @@ contract LiquidityProviderSampler is
}
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
/// @param registryAddress Address of the liquidity provider registry contract.
/// @param providerAddress Address of the liquidity provider.
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param makerTokenAmounts Maker token buy amount for each sample.
/// @return takerTokenAmounts Taker amounts sold at each maker token
/// amount.
function sampleBuysFromLiquidityProviderRegistry(
address registryAddress,
function sampleBuysFromLiquidityProvider(
address providerAddress,
address takerToken,
address makerToken,
uint256[] memory makerTokenAmounts
)
public
view
returns (uint256[] memory takerTokenAmounts, address providerAddress)
returns (uint256[] memory takerTokenAmounts)
{
providerAddress = _getLiquidityProviderFromRegistry(
registryAddress,
takerToken,
makerToken
);
takerTokenAmounts = _sampleApproximateBuys(
ApproximateBuyQuoteOpts({
makerTokenData: abi.encode(makerToken, registryAddress),
takerTokenData: abi.encode(takerToken, registryAddress),
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProviderRegistry
makerTokenData: abi.encode(makerToken, providerAddress),
takerTokenData: abi.encode(takerToken, providerAddress),
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProvider
}),
makerTokenAmounts
);
}
/// @dev Returns the address of a liquidity provider for the given market
/// (takerToken, makerToken), from a registry of liquidity providers.
/// Returns address(0) if no such provider exists in the registry.
/// @param takerToken Taker asset managed by liquidity provider.
/// @param makerToken Maker asset managed by liquidity provider.
/// @return providerAddress Address of the liquidity provider.
function _getLiquidityProviderFromRegistry(
address registryAddress,
address takerToken,
address makerToken
)
private
view
returns (address providerAddress)
{
if (registryAddress == address(0)) {
return address(0);
}
bytes memory callData = abi.encodeWithSelector(
ILiquidityProviderRegistry.getLiquidityProviderForMarket.selector,
takerToken,
makerToken
);
(bool didSucceed, bytes memory returnData) = registryAddress.staticcall(callData);
if (didSucceed && returnData.length == 32) {
return LibBytesV06.readAddress(returnData, 12);
}
}
function _sampleSellForApproximateBuyFromLiquidityProviderRegistry(
function _sampleSellForApproximateBuyFromLiquidityProvider(
bytes memory takerTokenData,
bytes memory makerTokenData,
uint256 sellAmount
@@ -151,15 +104,15 @@ contract LiquidityProviderSampler is
view
returns (uint256 buyAmount)
{
(address takerToken, address plpRegistryAddress) =
(address takerToken, address providerAddress) =
abi.decode(takerTokenData, (address, address));
(address makerToken) =
abi.decode(makerTokenData, (address));
try
this.sampleSellsFromLiquidityProviderRegistry
this.sampleSellsFromLiquidityProvider
{gas: DEFAULT_CALL_GAS}
(plpRegistryAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
returns (uint256[] memory amounts, address)
(providerAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
returns (uint256[] memory amounts)
{
return amounts[0];
} catch (bytes memory) {

View File

@@ -1,70 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
interface ILiquidityProvider {
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
/// @param tokenAddress The address of the ERC20 token to transfer.
/// @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
)
external
returns (bytes4 success);
/// @dev Quotes the amount of `makerToken` that would be obtained by
/// selling `sellAmount` of `takerToken`.
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param sellAmount Amount of `takerToken` to sell.
/// @return makerTokenAmount Amount of `makerToken` that would be obtained.
function getSellQuote(
address takerToken,
address makerToken,
uint256 sellAmount
)
external
view
returns (uint256 makerTokenAmount);
/// @dev Quotes the amount of `takerToken` that would need to be sold in
/// order to obtain `buyAmount` of `makerToken`.
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param buyAmount Amount of `makerToken` to buy.
/// @return takerTokenAmount Amount of `takerToken` that would need to be sold.
function getBuyQuote(
address takerToken,
address makerToken,
uint256 buyAmount
)
external
view
returns (uint256 takerTokenAmount);
}

View File

@@ -1,36 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
interface ILiquidityProviderRegistry {
/// @dev Returns the address of a liquidity provider for the given market
/// (takerToken, makerToken), reverting if the pool does not exist.
/// @param takerToken Taker asset managed by liquidity provider.
/// @param makerToken Maker asset managed by liquidity provider.
/// @return providerAddress Address of the liquidity provider.
function getLiquidityProviderForMarket(
address takerToken,
address makerToken
)
external
view
returns (address providerAddress);
}

View File

@@ -1,44 +0,0 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
contract DummyLiquidityProviderRegistry
{
address private constant NULL_ADDRESS = address(0x0);
mapping (address => mapping (address => address)) internal _gAddressBook;
/// @dev Sets address of pool for a market given market (xAsset, yAsset).
/// @param xToken First asset managed by pool.
/// @param yToken Second asset managed by pool.
/// @param poolAddress Address of pool.
function setLiquidityProviderForMarket(
address xToken,
address yToken,
address poolAddress
)
external
{
_gAddressBook[xToken][yToken] = poolAddress;
_gAddressBook[yToken][xToken] = poolAddress;
}
/// @dev Returns the address of pool for a market given market (xAsset, yAsset), or reverts if pool does not exist.
/// @param xToken First asset managed by pool.
/// @param yToken Second asset managed by pool.
/// @return poolAddress Address of pool.
function getLiquidityProviderForMarket(
address xToken,
address yToken
)
external
view
returns (address poolAddress)
{
poolAddress = _gAddressBook[xToken][yToken];
require(
poolAddress != NULL_ADDRESS,
"Registry/MARKET_PAIR_NOT_SET"
);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/asset-swapper",
"version": "5.0.1",
"version": "5.1.0",
"engines": {
"node": ">=6.12"
},
@@ -36,9 +36,9 @@
"publish:private": "yarn build && gitpkg publish"
},
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
"publicInterfaceContracts": "ERC20BridgeSampler",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
"postpublish": {
"assets": []
}
@@ -59,11 +59,11 @@
"dependencies": {
"@0x/assert": "^3.0.17",
"@0x/base-contract": "^6.2.11",
"@0x/contract-addresses": "^5.1.0",
"@0x/contract-wrappers": "^13.9.4",
"@0x/contract-addresses": "^5.3.0",
"@0x/contract-wrappers": "^13.10.0",
"@0x/dev-utils": "^4.0.1",
"@0x/json-schemas": "^5.3.3",
"@0x/order-utils": "^10.4.4",
"@0x/order-utils": "^10.4.6",
"@0x/orderbook": "^2.2.7",
"@0x/quote-server": "^3.1.0",
"@0x/types": "^3.3.0",
@@ -87,15 +87,16 @@
},
"devDependencies": {
"@0x/base-contract": "^6.2.11",
"@0x/contracts-asset-proxy": "^3.6.3",
"@0x/contracts-erc20": "^3.2.6",
"@0x/contracts-exchange": "^3.2.12",
"@0x/contracts-exchange-libs": "^4.3.12",
"@0x/contracts-asset-proxy": "^3.6.5",
"@0x/contracts-erc20": "^3.2.8",
"@0x/contracts-exchange": "^3.2.14",
"@0x/contracts-exchange-libs": "^4.3.14",
"@0x/contracts-gen": "^2.0.18",
"@0x/contracts-test-utils": "^5.3.9",
"@0x/contracts-utils": "^4.5.6",
"@0x/contracts-test-utils": "^5.3.11",
"@0x/contracts-utils": "^4.5.8",
"@0x/contracts-zero-ex": "^0.9.0",
"@0x/mesh-rpc-client": "^9.4.2",
"@0x/migrations": "^6.4.6",
"@0x/migrations": "^6.5.0",
"@0x/sol-compiler": "^4.2.7",
"@0x/subproviders": "^6.1.9",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -5,15 +5,5 @@
*/
import { ContractArtifact } from 'ethereum-types';
import * as DummyLiquidityProvider from '../generated-artifacts/DummyLiquidityProvider.json';
import * as DummyLiquidityProviderRegistry from '../generated-artifacts/DummyLiquidityProviderRegistry.json';
import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json';
import * as ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json';
import * as ILiquidityProviderRegistry from '../generated-artifacts/ILiquidityProviderRegistry.json';
export const artifacts = {
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact,
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
};
export const artifacts = { ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact };

View File

@@ -90,7 +90,10 @@ const DEFAULT_SWAP_QUOTE_REQUEST_OPTS: SwapQuoteRequestOpts = {
const DEFAULT_RFQT_REQUEST_OPTS: Partial<RfqtRequestOpts> = {
makerEndpointMaxResponseTimeMs: 1000,
isPriceAwareRFQEnabled: false,
priceAwareRFQFlag: {
isFirmPriceAwareEnabled: false,
isIndicativePriceAwareEnabled: false,
},
};
export const DEFAULT_INFO_LOGGER: LogFunction = (obj, msg) =>

View File

@@ -147,10 +147,10 @@ export {
GetMarketOrdersRfqtOpts,
KyberFillData,
LiquidityProviderFillData,
LiquidityProviderRegistry,
MarketDepth,
MarketDepthSide,
MooniswapFillData,
MultiBridgeFillData,
MultiHopFillData,
NativeCollapsedFill,
NativeFillData,

View File

@@ -34,7 +34,7 @@ import { getSwapMinBuyAmount } from './utils';
// tslint:disable-next-line:custom-no-magic-numbers
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
const { NULL_ADDRESS, ZERO_AMOUNT } = constants;
const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
public readonly provider: ZeroExProvider;
@@ -96,9 +96,16 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
const buyToken = getTokenFromAssetData(quote.makerAssetData);
const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount;
let minBuyAmount = getSwapMinBuyAmount(quote);
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
if (isFromETH) {
ethAmount = ethAmount.plus(sellAmount);
}
const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
// VIP routes.
if (isDirectUniswapCompatible(quote, optsWithDefaults)) {
if (
isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap])
) {
const source = quote.orders[0].fills[0].source;
const fillData = quote.orders[0].fills[0].fillData as UniswapV2FillData;
return {
@@ -124,6 +131,26 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
};
}
if (isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.LiquidityProvider])) {
const target = quote.orders[0].makerAddress;
return {
calldataHexString: this._exchangeProxy
.sellToLiquidityProvider(
isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
isToETH ? ETH_TOKEN_ADDRESS : buyToken,
target,
NULL_ADDRESS,
sellAmount,
minBuyAmount,
NULL_BYTES,
)
.getABIEncodedTransactionData(),
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
toAddress: this._exchangeProxy.address,
allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget,
};
}
// Build up the transforms.
const transforms = [];
if (isFromETH) {
@@ -198,8 +225,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}
// This transformer pays affiliate fees.
const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
if (buyTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
transforms.push({
deploymentNonce: this.transformerNonces.affiliateFeeTransformer,
@@ -216,7 +241,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
// Adjust the minimum buy amount by the fee.
minBuyAmount = BigNumber.max(0, minBuyAmount.minus(buyTokenFeeAmount));
}
if (sellTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
throw new Error('Affiliate fees denominated in sell token are not yet supported');
}
@@ -240,11 +264,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
)
.getABIEncodedTransactionData();
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
if (isFromETH) {
ethAmount = ethAmount.plus(sellAmount);
}
return {
calldataHexString,
ethAmount,
@@ -266,7 +285,11 @@ function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote {
return quote.type === MarketOperation.Buy;
}
function isDirectUniswapCompatible(quote: SwapQuote, opts: ExchangeProxyContractOpts): boolean {
function isDirectSwapCompatible(
quote: SwapQuote,
opts: ExchangeProxyContractOpts,
directSources: ERC20BridgeSource[],
): boolean {
// Must not be a mtx.
if (opts.isMetaTransaction) {
return false;
@@ -285,8 +308,7 @@ function isDirectUniswapCompatible(quote: SwapQuote, opts: ExchangeProxyContract
return false;
}
const fill = order.fills[0];
// And that fill must be uniswap v2 or sushiswap.
if (![ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap].includes(fill.source)) {
if (!directSources.includes(fill.source)) {
return false;
}
return true;

View File

@@ -5,7 +5,7 @@ import { MarketOperation, SwapQuote } from '../types';
import { ERC20BridgeSource } from '../utils/market_operation_utils/types';
/**
* Compute the mminimum buy token amount for market operations by inferring
* Compute the minimum buy token amount for market operations by inferring
* the slippage from the orders in a quote. We cannot rely on
* `worstCaseQuoteInfo.makerAssetAmount` because that does not stop at
* maximum slippage.

View File

@@ -41,6 +41,7 @@ import { ProtocolFeeUtils } from './utils/protocol_fee_utils';
import { QuoteRequestor } from './utils/quote_requestor';
import { sortingUtils } from './utils/sorting_utils';
import { SwapQuoteCalculator } from './utils/swap_quote_calculator';
import { getPriceAwareRFQRolloutFlags } from './utils/utils';
import { ERC20BridgeSamplerContract } from './wrappers';
export class SwapQuoter {
@@ -164,8 +165,9 @@ export class SwapQuoter {
expiryBufferMs,
permittedOrderFeeTypes,
samplerGasLimit,
liquidityProviderRegistryAddress,
rfqt,
tokenAdjacencyGraph,
liquidityProviderRegistry,
} = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
const provider = providerUtils.standardizeOrThrow(supportedProvider);
assert.isValidOrderbook('orderbook', orderbook);
@@ -207,13 +209,21 @@ export class SwapQuoter {
},
);
this._marketOperationUtils = new MarketOperationUtils(
new DexOrderSampler(samplerContract, samplerOverrides, provider),
new DexOrderSampler(
samplerContract,
samplerOverrides,
provider,
undefined,
undefined,
undefined,
tokenAdjacencyGraph,
liquidityProviderRegistry,
),
this._contractAddresses,
{
chainId,
exchangeAddress: this._contractAddresses.exchange,
},
liquidityProviderRegistryAddress,
);
this._swapQuoteCalculator = new SwapQuoteCalculator(this._marketOperationUtils);
}
@@ -700,7 +710,7 @@ export class SwapQuoter {
if (
opts.rfqt && // This is an RFQT-enabled API request
!opts.rfqt.isPriceAwareRFQEnabled && // If Price-aware RFQ is enabled, firm quotes are requested later on in the process.
!getPriceAwareRFQRolloutFlags(opts.rfqt.priceAwareRFQFlag).isFirmPriceAwareEnabled && // If Price-aware RFQ is enabled, firm quotes are requested later on in the process.
opts.rfqt.intentOnFilling && // The requestor is asking for a firm quote
opts.rfqt.apiKey &&
this._isApiKeyWhitelisted(opts.rfqt.apiKey) && // A valid API key was provided

View File

@@ -4,7 +4,13 @@ import { TakerRequestQueryParams } from '@0x/quote-server';
import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { ERC20BridgeSource, GetMarketOrdersOpts, OptimizedMarketOrder } from './utils/market_operation_utils/types';
import {
ERC20BridgeSource,
GetMarketOrdersOpts,
LiquidityProviderRegistry,
OptimizedMarketOrder,
TokenAdjacencyGraph,
} from './utils/market_operation_utils/types';
import { QuoteReport } from './utils/quote_report_generator';
/**
@@ -234,6 +240,11 @@ export type SwapQuoteOrdersBreakdown = Partial<
}
>;
export interface PriceAwareRFQFlags {
isIndicativePriceAwareEnabled: boolean;
isFirmPriceAwareEnabled: boolean;
}
/**
* nativeExclusivelyRFQT: if set to `true`, Swap quote will exclude Open Orderbook liquidity.
* If set to `true` and `ERC20BridgeSource.Native` is part of the `excludedSources`
@@ -256,7 +267,7 @@ export interface RfqtRequestOpts {
* the feature flag. When that time comes, follow this PR to "undo" the feature flag:
* https://github.com/0xProject/0x-monorepo/pull/2735
*/
isPriceAwareRFQEnabled?: boolean;
priceAwareRFQFlag?: PriceAwareRFQFlags;
}
/**
@@ -305,11 +316,12 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
ethereumRpcUrl?: string;
contractAddresses?: AssetSwapperContractAddresses;
samplerGasLimit?: number;
liquidityProviderRegistryAddress?: string;
multiBridgeAddress?: string;
ethGasStationUrl?: string;
rfqt?: SwapQuoterRfqtOpts;
samplerOverrides?: SamplerOverrides;
tokenAdjacencyGraph?: TokenAdjacencyGraph;
liquidityProviderRegistry?: LiquidityProviderRegistry;
}
/**

View File

@@ -13,6 +13,7 @@ import {
FeeSchedule,
FillData,
GetMarketOrdersOpts,
LiquidityProviderRegistry,
MultiHopFillData,
SnowSwapFillData,
SushiSwapFillData,
@@ -24,8 +25,7 @@ import {
/**
* Valid sources for market sell.
*/
export const SELL_SOURCE_FILTER = new SourceFilters(
[
export const SELL_SOURCE_FILTER = new SourceFilters([
ERC20BridgeSource.Native,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
@@ -44,15 +44,13 @@ export const SELL_SOURCE_FILTER = new SourceFilters(
ERC20BridgeSource.MultiHop,
ERC20BridgeSource.Dodo,
ERC20BridgeSource.Cream,
],
[ERC20BridgeSource.MultiBridge],
);
ERC20BridgeSource.LiquidityProvider,
]);
/**
* Valid sources for market buy.
*/
export const BUY_SOURCE_FILTER = new SourceFilters(
[
export const BUY_SOURCE_FILTER = new SourceFilters([
ERC20BridgeSource.Native,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
@@ -70,9 +68,8 @@ export const BUY_SOURCE_FILTER = new SourceFilters(
ERC20BridgeSource.MultiHop,
ERC20BridgeSource.Dodo,
ERC20BridgeSource.Cream,
],
[ERC20BridgeSource.MultiBridge],
);
ERC20BridgeSource.LiquidityProvider,
]);
/**
* 0x Protocol Fee Multiplier
@@ -98,29 +95,60 @@ export const TOKENS = {
USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7',
sUSD: '0x57ab1ec28d129707052df4df418d58a2d46d5f51',
BUSD: '0x4fabb145d64652a948d72533023f6e7a623c7c53',
TUSD: '0x0000000000085d4780b73119b644ae5ecd22b376',
PAX: '0x8e870d67f660d95d5be530380d0ec0bd388289e1',
GUSD: '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd',
HUSD: '0xdf574c24545e5ffecb9a659c229253d4111d87e1',
mUSD: '0xe2f2a5c287993345a840db3b0845fbc70f5935a5',
USDN: '0x674c6ad92fd080e4004b2312b45f796a192d27a0',
// Bitcoins
WBTC: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
RenBTC: '0xeb4c2781e4eba804ce9a9803c67d0893436bb27d',
sBTC: '0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6',
tBTC: '0x8daebade922df735c38c80c7ebd708af50815faa',
hBTC: '0x0316eb71485b0ab14103307bf65a021042c6d380',
// Other
MKR: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
};
export const POOLS = {
// following the same order in curve.fi:
curve_compound: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56',
// curve_USDT: '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c',
curve_PAX: '0x06364f10b501e868329afbc005b3492902d6c763',
curve_y: '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51',
curve_BUSD: '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27',
curve_sUSD: '0xa5407eae9ba41422680e2e00537571bcc53efbfd',
curve_renBTC: '0x93054188d876f558f4a66b2ef1d97d16edf0895b',
curve_sBTC: '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714',
curve_HBTC: '0x4ca9b3063ec5866a4b82e437059d2c43d1be596f',
curve_TRI: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7',
curve_GUSD: '0x4f062658eaaf2c1ccf8c8e36d6824cdf41167956',
curve_HUSD: '0x3ef6a01a0f81d6046290f3e2a8c5b843e738e604',
// 12.usdk is dead
curve_USDN: '0x0f9cb53ebe405d49a0bbdbd291a65ff571bc83e1',
// 14.linkusd is dead
curve_mUSD: '0x8474ddbe98f5aa3179b3b3f5942d724afcdec9f6',
// 16.rsv is dead
curve_tBTC: '0xc25099792e9349c7dd09759744ea681c7de2cb66',
};
/**
* Mainnet Curve configuration
* The tokens are in order of their index, which each curve defines
* I.e DaiUsdc curve has DAI as index 0 and USDC as index 1
*/
export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = {
DaiUsdc: {
[POOLS.curve_compound]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
poolAddress: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56',
poolAddress: POOLS.curve_compound,
tokens: [TOKENS.DAI, TOKENS.USDC],
metaToken: undefined,
},
// DaiUsdcUsdt: {
// USDT: {
// exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
// sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
// buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
@@ -131,53 +159,110 @@ export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = {
// TOKENS.USDT,
// ],
// },
DaiUsdcUsdtTusd: {
[POOLS.curve_PAX]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_PAX,
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.PAX],
metaToken: undefined,
},
[POOLS.curve_y]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
poolAddress: '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51',
poolAddress: POOLS.curve_y,
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.TUSD],
metaToken: undefined,
},
// Looks like it's dying.
DaiUsdcUsdtBusd: {
[POOLS.curve_BUSD]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
poolAddress: '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27',
tokens: [
TOKENS.DAI,
TOKENS.USDC,
TOKENS.USDT,
'0x4fabb145d64652a948d72533023f6e7a623c7c53', // bUSD
],
poolAddress: POOLS.curve_BUSD,
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.BUSD],
metaToken: undefined,
},
DaiUsdcUsdtSusd: {
[POOLS.curve_sUSD]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: '0xa5407eae9ba41422680e2e00537571bcc53efbfd',
poolAddress: POOLS.curve_sUSD,
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.sUSD],
metaToken: undefined,
},
RenbtcWbtc: {
[POOLS.curve_renBTC]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: '0x93054188d876f558f4a66b2ef1d97d16edf0895b',
poolAddress: POOLS.curve_renBTC,
tokens: [TOKENS.RenBTC, TOKENS.WBTC],
metaToken: undefined,
},
RenbtcWbtcSbtc: {
[POOLS.curve_sBTC]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714',
poolAddress: POOLS.curve_sBTC,
tokens: [TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC],
metaToken: undefined,
},
TriPool: {
[POOLS.curve_HBTC]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7',
poolAddress: POOLS.curve_HBTC,
tokens: [TOKENS.hBTC, TOKENS.WBTC],
metaToken: undefined,
},
[POOLS.curve_TRI]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_TRI,
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: undefined,
},
// Metapools
[POOLS.curve_GUSD]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_GUSD,
tokens: [TOKENS.GUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: TOKENS.GUSD,
},
[POOLS.curve_HUSD]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_HUSD,
tokens: [TOKENS.HUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: TOKENS.HUSD,
},
[POOLS.curve_USDN]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_USDN,
tokens: [TOKENS.USDN, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: TOKENS.USDN,
},
[POOLS.curve_mUSD]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_mUSD,
tokens: [TOKENS.mUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: TOKENS.mUSD,
},
[POOLS.curve_tBTC]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_tBTC,
tokens: [TOKENS.tBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC],
metaToken: TOKENS.tBTC,
},
};
@@ -188,6 +273,7 @@ export const MAINNET_SWERVE_INFOS: { [name: string]: CurveInfo } = {
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: '0x329239599afb305da0a2ec69c58f8a6697f9f88d', // _target: 0xa5407eae9ba41422680e2e00537571bcc53efbfd
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.TUSD],
metaToken: undefined,
},
};
@@ -201,6 +287,7 @@ export const MAINNET_SNOWSWAP_INFOS: { [name: string]: CurveInfo } = {
'0x5dbcf33d8c2e976c6b560249878e6f1491bca25c', // yUSD
'0x2994529c0652d127b7842094103715ec5299bbed', // ybCRV
],
metaToken: undefined,
},
yVaultCurveUnderlying: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
@@ -211,6 +298,7 @@ export const MAINNET_SNOWSWAP_INFOS: { [name: string]: CurveInfo } = {
'0xdf5e0e81dff6faf3a7e52ba697820c5e32d806a8', // yCRV
'0x3b3ac5386837dc563660fb6a0937dfaa5924333b', // bCRV
],
metaToken: undefined,
},
yVaultUSD: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
@@ -223,20 +311,8 @@ export const MAINNET_SNOWSWAP_INFOS: { [name: string]: CurveInfo } = {
'0x2f08119c6f07c006695e079aafc638b8789faf18', // yUSDT
'0x37d19d1c4e1fa9dc47bd1ea12f742a0887eda74a', // yTUSD
],
metaToken: undefined,
},
// Gas is too high for these underlying tokens (3M+)
// yVaultUSDUnderlying: {
// exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
// sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
// buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
// poolAddress: '0x4571753311e37ddb44faa8fb78a6df9a6e3c6c0b',
// tokens: [
// TOKENS.DAI,
// TOKENS.USDC,
// TOKENS.USDT,
// TOKENS.TUSD,
// ],
// },
};
export const MAINNET_KYBER_RESERVE_IDS: { [name: string]: string } = {
@@ -273,6 +349,8 @@ export const MAINNET_KYBER_TOKEN_RESERVE_IDS: { [token: string]: string } = {
'0xaa42414e44000000000000000000000000000000000000000000000000000000',
};
export const LIQUIDITY_PROVIDER_REGISTRY: LiquidityProviderRegistry = {};
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
export const MAINNET_SHELL_POOLS = {
@@ -361,19 +439,25 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
[ERC20BridgeSource.Curve]: fillData => {
const poolAddress = (fillData as CurveFillData).pool.poolAddress.toLowerCase();
switch (poolAddress) {
case '0xa5407eae9ba41422680e2e00537571bcc53efbfd':
case '0x93054188d876f558f4a66b2ef1d97d16edf0895b':
case '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714':
case '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7':
case POOLS.curve_renBTC:
case POOLS.curve_sBTC:
case POOLS.curve_sUSD:
case POOLS.curve_HBTC:
case POOLS.curve_TRI:
return 150e3;
case '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56':
case POOLS.curve_compound:
return 750e3;
case '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51':
case POOLS.curve_PAX:
case POOLS.curve_y:
case POOLS.curve_BUSD:
return 850e3;
case '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27':
return 1e6;
case '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c':
return 600e3;
// Metapools
case POOLS.curve_GUSD:
case POOLS.curve_HUSD:
case POOLS.curve_USDN:
case POOLS.curve_mUSD:
case POOLS.curve_tBTC:
return 650e3;
default:
throw new Error(`Unrecognized Curve address: ${poolAddress}`);
}
@@ -459,5 +543,5 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
exchangeProxyOverhead: () => ZERO_AMOUNT,
allowFallback: true,
shouldGenerateQuoteReport: false,
tokenAdjacencyGraph: {},
tokenAdjacencyGraph: { default: [] },
};

View File

@@ -3,13 +3,31 @@ import { CurveInfo, SnowSwapInfo, SwerveInfo } from './types';
// tslint:disable completed-docs
export function getCurveInfosForPair(takerToken: string, makerToken: string): CurveInfo[] {
return Object.values(MAINNET_CURVE_INFOS).filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)));
return Object.values(MAINNET_CURVE_INFOS).filter(c =>
[makerToken, takerToken].every(
t =>
(c.tokens.includes(t) && c.metaToken === undefined) ||
(c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)),
),
);
}
export function getSwerveInfosForPair(takerToken: string, makerToken: string): SwerveInfo[] {
return Object.values(MAINNET_SWERVE_INFOS).filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)));
return Object.values(MAINNET_SWERVE_INFOS).filter(c =>
[makerToken, takerToken].every(
t =>
(c.tokens.includes(t) && c.metaToken === undefined) ||
(c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)),
),
);
}
export function getSnowSwapInfosForPair(takerToken: string, makerToken: string): SnowSwapInfo[] {
return Object.values(MAINNET_SNOWSWAP_INFOS).filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)));
return Object.values(MAINNET_SNOWSWAP_INFOS).filter(c =>
[makerToken, takerToken].every(
t =>
(c.tokens.includes(t) && c.metaToken === undefined) ||
(c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)),
),
);
}

View File

@@ -6,6 +6,7 @@ import * as _ from 'lodash';
import { AssetSwapperContractAddresses, MarketOperation, Omit } from '../../types';
import { QuoteRequestor } from '../quote_requestor';
import { getPriceAwareRFQRolloutFlags } from '../utils';
import { generateQuoteReport, QuoteReport } from './../quote_report_generator';
import {
@@ -77,7 +78,6 @@ export async function getRfqtIndicativeQuotesAsync(
export class MarketOperationUtils {
private readonly _wethAddress: string;
private readonly _multiBridge: string;
private readonly _sellSources: SourceFilters;
private readonly _buySources: SourceFilters;
private readonly _feeSources = new SourceFilters(FEE_QUOTE_SOURCES);
@@ -107,19 +107,10 @@ export class MarketOperationUtils {
private readonly _sampler: DexOrderSampler,
private readonly contractAddresses: AssetSwapperContractAddresses,
private readonly _orderDomain: OrderDomain,
private readonly _liquidityProviderRegistry: string = NULL_ADDRESS,
) {
this._wethAddress = contractAddresses.etherToken.toLowerCase();
this._multiBridge = contractAddresses.multiBridge.toLowerCase();
const optionalQuoteSources = [];
if (this._liquidityProviderRegistry !== NULL_ADDRESS) {
optionalQuoteSources.push(ERC20BridgeSource.LiquidityProvider);
}
if (this._multiBridge !== NULL_ADDRESS) {
optionalQuoteSources.push(ERC20BridgeSource.MultiBridge);
}
this._buySources = BUY_SOURCE_FILTER.validate(optionalQuoteSources);
this._sellSources = SELL_SOURCE_FILTER.validate(optionalQuoteSources);
this._buySources = BUY_SOURCE_FILTER;
this._sellSources = SELL_SOURCE_FILTER;
}
/**
@@ -175,46 +166,26 @@ export class MarketOperationUtils {
// Get native order fillable amounts.
this._sampler.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchange),
// Get ETH -> maker token price.
this._sampler.getMedianSellRate(
feeSourceFilters.sources,
makerToken,
this._wethAddress,
ONE_ETHER,
this._liquidityProviderRegistry,
this._multiBridge,
),
this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER),
// Get ETH -> taker token price.
this._sampler.getMedianSellRate(
feeSourceFilters.sources,
takerToken,
this._wethAddress,
ONE_ETHER,
this._liquidityProviderRegistry,
this._multiBridge,
),
this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER),
// Get sell quotes for taker -> maker.
this._sampler.getSellQuotes(
quoteSourceFilters.exclude(offChainSources).sources,
makerToken,
takerToken,
sampleAmounts,
this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry,
this._multiBridge,
),
this._sampler.getTwoHopSellQuotes(
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
makerToken,
takerToken,
takerAmount,
this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry,
),
);
const isPriceAwareRfqEnabled = _opts.rfqt && _opts.rfqt.isPriceAwareRFQEnabled;
const isPriceAwareRfqEnabled =
_opts.rfqt && getPriceAwareRFQRolloutFlags(_opts.rfqt.priceAwareRFQFlag).isIndicativePriceAwareEnabled;
const rfqtPromise =
!isPriceAwareRfqEnabled && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)
? getRfqtIndicativeQuotesAsync(
@@ -325,44 +296,25 @@ export class MarketOperationUtils {
// Get native order fillable amounts.
this._sampler.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchange),
// Get ETH -> makerToken token price.
this._sampler.getMedianSellRate(
feeSourceFilters.sources,
makerToken,
this._wethAddress,
ONE_ETHER,
this._liquidityProviderRegistry,
this._multiBridge,
),
this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER),
// Get ETH -> taker token price.
this._sampler.getMedianSellRate(
feeSourceFilters.sources,
takerToken,
this._wethAddress,
ONE_ETHER,
this._liquidityProviderRegistry,
this._multiBridge,
),
this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER),
// Get buy quotes for taker -> maker.
this._sampler.getBuyQuotes(
quoteSourceFilters.exclude(offChainSources).sources,
makerToken,
takerToken,
sampleAmounts,
this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry,
),
this._sampler.getTwoHopBuyQuotes(
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
makerToken,
takerToken,
makerAmount,
this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry,
),
);
const isPriceAwareRfqEnabled = _opts.rfqt && _opts.rfqt.isPriceAwareRFQEnabled;
const isPriceAwareRfqEnabled =
_opts.rfqt && getPriceAwareRFQRolloutFlags(_opts.rfqt.priceAwareRFQFlag).isIndicativePriceAwareEnabled;
const rfqtPromise =
!isPriceAwareRfqEnabled && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)
? getRfqtIndicativeQuotesAsync(
@@ -388,10 +340,6 @@ export class MarketOperationUtils {
offChainBalancerQuotes,
offChainCreamQuotes,
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainCreamPromise]);
// Attach the MultiBridge address to the sample fillData
(dexQuotes.find(quotes => quotes[0] && quotes[0].source === ERC20BridgeSource.MultiBridge) || []).forEach(
q => (q.fillData = { poolAddress: this._multiBridge }),
);
const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
return {
side: MarketOperation.Buy,
@@ -479,7 +427,6 @@ export class MarketOperationUtils {
getNativeOrderTokens(orders[0])[1],
this._wethAddress,
ONE_ETHER,
this._wethAddress,
),
),
...batchNativeOrders.map((orders, i) =>
@@ -488,8 +435,6 @@ export class MarketOperationUtils {
getNativeOrderTokens(orders[0])[0],
getNativeOrderTokens(orders[0])[1],
[makerAmounts[i]],
this._wethAddress,
_opts.tokenAdjacencyGraph,
),
),
];
@@ -677,12 +622,7 @@ export class MarketOperationUtils {
// If RFQ liquidity is enabled, make a request to check RFQ liquidity
let comparisonPrice: BigNumber | undefined;
const { rfqt } = _opts;
if (
rfqt &&
rfqt.isPriceAwareRFQEnabled &&
rfqt.quoteRequestor &&
marketSideLiquidity.quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)
) {
if (rfqt && rfqt.quoteRequestor && marketSideLiquidity.quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)) {
// Calculate a suggested price. For now, this is simply the overall price of the aggregation.
if (optimizerResult) {
const totalMakerAmount = BigNumber.sum(
@@ -706,8 +646,12 @@ export class MarketOperationUtils {
}
}
// If we are making an indicative quote, make the RFQT request and then re-run the sampler if new orders come back.
if (rfqt.isIndicative) {
const { isFirmPriceAwareEnabled, isIndicativePriceAwareEnabled } = getPriceAwareRFQRolloutFlags(
rfqt.priceAwareRFQFlag,
);
if (rfqt.isIndicative && isIndicativePriceAwareEnabled) {
// An indicative quote is beingh requested, and indicative quotes price-aware enabled. Make the RFQT request and then re-run the sampler if new orders come back.
const indicativeQuotes = await getRfqtIndicativeQuotesAsync(
nativeOrders[0].makerAssetData,
nativeOrders[0].takerAssetData,
@@ -726,8 +670,8 @@ export class MarketOperationUtils {
optimizerOpts,
);
}
} else {
// A firm quote is being requested. Ensure that `intentOnFilling` is enabled.
} else if (!rfqt.isIndicative && isFirmPriceAwareEnabled) {
// A firm quote is being requested, and firm quotes price-aware enabled. Ensure that `intentOnFilling` is enabled.
if (rfqt.intentOnFilling) {
// Extra validation happens when requesting a firm quote, such as ensuring that the takerAddress
// is indeed valid.

View File

@@ -0,0 +1,12 @@
import { LiquidityProviderRegistry } from './types';
// tslint:disable completed-docs
export function getLiquidityProvidersForPair(
registry: LiquidityProviderRegistry,
takerToken: string,
makerToken: string,
): string[] {
return Object.entries(registry)
.filter(([, tokens]) => [makerToken, takerToken].every(t => tokens.includes(t)))
.map(([providerAddress]) => providerAddress);
}

View File

@@ -1,13 +0,0 @@
import { NULL_ADDRESS, TOKENS } from './constants';
// tslint:disable completed-docs
export function getMultiBridgeIntermediateToken(takerToken: string, makerToken: string): string {
let intermediateToken = NULL_ADDRESS;
if (takerToken !== TOKENS.WETH && makerToken !== TOKENS.WETH) {
intermediateToken = TOKENS.WETH;
} else if (takerToken === TOKENS.USDC || makerToken === TOKENS.USDC) {
intermediateToken = TOKENS.DAI;
}
return intermediateToken;
}

View File

@@ -21,19 +21,11 @@ export function getIntermediateTokens(
makerToken: string,
takerToken: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
wethAddress: string,
): string[] {
let intermediateTokens = [];
if (makerToken === wethAddress) {
intermediateTokens = _.get(tokenAdjacencyGraph, takerToken, [] as string[]);
} else if (takerToken === wethAddress) {
intermediateTokens = _.get(tokenAdjacencyGraph, makerToken, [] as string[]);
} else {
intermediateTokens = _.union(
_.intersection(_.get(tokenAdjacencyGraph, takerToken, []), _.get(tokenAdjacencyGraph, makerToken, [])),
[wethAddress],
const intermediateTokens = _.intersection(
_.get(tokenAdjacencyGraph, takerToken, tokenAdjacencyGraph.default),
_.get(tokenAdjacencyGraph, makerToken, tokenAdjacencyGraph.default),
);
}
return _.uniqBy(intermediateTokens, a => a.toLowerCase()).filter(
token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(),
);

View File

@@ -15,7 +15,6 @@ import {
WALLET_SIGNATURE,
ZERO_AMOUNT,
} from './constants';
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
import {
AggregationError,
BalancerFillData,
@@ -28,7 +27,6 @@ import {
KyberFillData,
LiquidityProviderFillData,
MooniswapFillData,
MultiBridgeFillData,
MultiHopFillData,
NativeCollapsedFill,
OptimizedMarketOrder,
@@ -193,8 +191,6 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
return opts.contractAddresses.creamBridge;
case ERC20BridgeSource.LiquidityProvider:
return (fill.fillData as LiquidityProviderFillData).poolAddress;
case ERC20BridgeSource.MultiBridge:
return (fill.fillData as MultiBridgeFillData).poolAddress;
case ERC20BridgeSource.MStable:
return opts.contractAddresses.mStableBridge;
case ERC20BridgeSource.Mooniswap:
@@ -301,13 +297,6 @@ export function createBridgeOrder(
createSushiSwapBridgeData(sushiSwapFillData.tokenAddressPath, sushiSwapFillData.router),
);
break;
case ERC20BridgeSource.MultiBridge:
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
makerToken,
bridgeAddress,
createMultiBridgeData(takerToken, makerToken),
);
break;
case ERC20BridgeSource.Kyber:
const kyberFillData = (fill as CollapsedFill<KyberFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
@@ -372,15 +361,6 @@ function createBridgeData(tokenAddress: string): string {
return encoder.encode({ tokenAddress });
}
function createMultiBridgeData(takerToken: string, makerToken: string): string {
const intermediateToken = getMultiBridgeIntermediateToken(takerToken, makerToken);
const encoder = AbiEncoder.create([
{ name: 'takerToken', type: 'address' },
{ name: 'intermediateToken', type: 'address' },
]);
return encoder.encode({ takerToken, intermediateToken });
}
function createBalancerBridgeData(takerToken: string, poolAddress: string): string {
const encoder = AbiEncoder.create([
{ name: 'takerToken', type: 'address' },

Some files were not shown because too many files have changed in this diff Show More