Compare commits

..

6 Commits

Author SHA1 Message Date
Github Actions
b29196b983 Publish
- @0x/contracts-asset-proxy@3.7.6
 - @0x/contracts-broker@1.1.24
 - @0x/contracts-coordinator@3.1.25
 - @0x/contracts-dev-utils@1.3.23
 - @0x/contracts-erc1155@2.1.24
 - @0x/contracts-erc20@3.3.3
 - @0x/contracts-erc721@3.1.24
 - @0x/contracts-exchange-forwarder@4.2.25
 - @0x/contracts-exchange-libs@4.3.24
 - @0x/contracts-exchange@3.2.25
 - @0x/contracts-extensions@6.2.19
 - @0x/contracts-integrations@2.7.26
 - @0x/contracts-multisig@4.1.25
 - @0x/contracts-staking@2.0.32
 - @0x/contracts-test-utils@5.3.21
 - @0x/contracts-treasury@1.0.1
 - @0x/contracts-utils@4.7.3
 - @0x/contracts-zero-ex@0.18.2
 - @0x/asset-swapper@6.0.0
 - @0x/contract-addresses@5.10.0
 - @0x/contract-wrappers-test@12.2.36
 - @0x/contract-wrappers@13.12.3
 - @0x/migrations@6.6.0
 - @0x/order-utils@10.4.16
 - @0x/protocol-utils@1.2.0
2021-02-10 09:49:05 +00:00
Github Actions
ce76a7033d Updated CHANGELOGS & MD docs 2021-02-10 09:48:52 +00:00
Jacob Evans
3f4bb933d1 feat: v4 final (#136)
* v4 FillQuoteTransformer (#104)

* Update FQT to support v4 orders

* `@0x/contracts-zero-ex`: Tweak FQT
`@0x/contracts-zero-ex`: Drop `ERC20BridgeTransfer` event and add `PartialQuoteFill` event.

* `@0x/contracts-utils`: Add `LibSafeMathV06.downcastToUint128()`

* `@0x/protocol-utils`: Update transformer utils for V4 FQT

* `@0x/contracts-zero-ex`: Fixing FQT tests...

* `@0x/contracts-zero-ex`: rename FQT bridge event

* `@0x/contracts-zero-ex`: Un-`only` tests

* `@0x/migrations`: Update `BridgeAdapter` deployment

* `@0x/contracts-integrations`: Delete `mtx_tests`

* `@0x/protocol-utils`: Address review comments

* `@0x/contracts-zero-ex`: Address review comments

* `@0x/migrations`: Update migrations

Co-authored-by: Michael Zhu <mchl.zhu.96@gmail.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>

* v4: Asset-swapper (main branch) (#113)

* refactor quote_requestor

* WIP v4/asset-swapper: Clean up SwapQuoter and remove @0x/orderbook

* Start replacing SignedOrder everywhere

* wip: new order type

* wip

* remove order-utils from most places

* hack: Play around with VerboseX types (#119)

* hack: Play around with VerboseX types

* More hacks

* Fix up the bridgeData encodings

* Rework Orderbook return type

* feat: Don't charge a protocol fee for RFQ orders WIP (#121)

* fix simple build errors

* simplify types a little

* remove SwapQuoteCalculator: unnecessary abstraction

* Fix all ./src build errors; make types consistent

* export more types for use in 0x API; modify Orderbook interface

* stop overriding APIOrder

* feat: RFQ v4 + consolidated bridge encoders (#125)

* feat: check if taker address is contract

* Rework bridge data

* Worst case adjustments

* RFQT v4

* Future/v4 validate orders (#126)

* RFQT v4

* v4 validate native orders

* use default invalid signature

* refactor rfqt validations in swap quoter

* fix types

* fix RFQT unlisted api key

* remove priceAwareRFQFlag

* adjust maker/taker amounts

* update JSON schemas

* filter zero fillable orders

Co-authored-by: xianny <xianny@gmail.com>

* fix type export

Co-authored-by: xianny <xianny@gmail.com>

* remove order-utils as much as possible

* work on tests compile

* Comment out quote reporter test

* updated tests

* restore order-utils accidental changes

* some lints

* Remove old fill_test

* ts lint disable for now

* update quote report

* Re-enable quote report tests

* make fill data required field

* fix lint

* type guards

* force fillData as required

* fix lint

* fix naming

* exports

* adjust MultiBridge by slippage

* cleanups (checkpoint 1)

* cleanup types (checkpoint #2)

* remove unused deps

* `@0x/contract-addresses`: Deploy new FQT (#129)

Co-authored-by: Lawrence Forman <me@merklejerk.com>

* commit bump to republish

* DRY up the rfqt mocker

* fix: Balancer load top pools (#131)

* fix: Balancer load top 250 pools

* refetch top pools on an interval

Co-authored-by: Jacob Evans <jacob@dekz.net>
Co-authored-by: Kim Persson <kimpers@users.noreply.github.com>
Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>

* Update post rebase

* prettier

* Remove test helpers exported in asset-swapper

* Clean up from review comments

* prettier

* lint

* recreate rfqt mocker

* change merge and INVALID_SIGNATURE

Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
Co-authored-by: Michael Zhu <mchl.zhu.96@gmail.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Xianny <8582774+xianny@users.noreply.github.com>
Co-authored-by: Kim Persson <kimpers@users.noreply.github.com>
2021-02-10 19:20:15 +10:00
Greg Hysz
501b7b9b65 Updated releases (#133) 2021-02-08 18:32:21 -08:00
Daniel Pyrathon
c0ea88e864 lint fix (#130) 2021-02-05 09:56:35 -08:00
Lawrence Forman
48f8bea460 docs: Fix wrong method name for order signature generation (#128)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-02-02 23:30:26 -05:00
181 changed files with 6170 additions and 9538 deletions

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "3.7.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "3.7.5",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.7.6 - _February 10, 2021_
* Dependencies updated
## v3.7.5 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-asset-proxy",
"version": "3.7.5",
"version": "3.7.6",
"engines": {
"node": ">=6.12"
},
@@ -52,10 +52,10 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contract-wrappers": "^13.12.2",
"@0x/contract-wrappers": "^13.12.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
@@ -80,11 +80,11 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-erc1155": "^2.1.23",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-erc721": "^3.1.23",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/order-utils": "^10.4.15",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/order-utils": "^10.4.16",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "1.1.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "1.1.23",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.1.24 - _February 10, 2021_
* Dependencies updated
## v1.1.23 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-broker",
"version": "1.1.23",
"version": "1.1.24",
"engines": {
"node": ">=6.12"
},
@@ -52,14 +52,14 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-erc721": "^3.1.23",
"@0x/contracts-exchange": "^3.2.24",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -85,7 +85,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",
"ethereum-types": "^3.4.0"

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "3.1.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "3.1.24",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.25 - _February 10, 2021_
* Dependencies updated
## v3.1.24 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-coordinator",
"version": "3.1.24",
"version": "3.1.25",
"engines": {
"node": ">=6.12"
},
@@ -53,12 +53,12 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-dev-utils": "^1.3.22",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -84,10 +84,10 @@
"dependencies": {
"@0x/assert": "^3.0.21",
"@0x/base-contract": "^6.2.18",
"@0x/contract-addresses": "^5.9.0",
"@0x/contracts-exchange": "^3.2.24",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contract-addresses": "^5.10.0",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/json-schemas": "^5.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "1.3.23",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "1.3.22",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.3.23 - _February 10, 2021_
* Dependencies updated
## v1.3.22 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-dev-utils",
"version": "1.3.22",
"version": "1.3.23",
"engines": {
"node": ">=6.12"
},
@@ -43,10 +43,10 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/assert": "^3.0.21",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "2.1.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "2.1.23",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.1.24 - _February 10, 2021_
* Dependencies updated
## v2.1.23 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc1155",
"version": "2.1.23",
"version": "2.1.24",
"engines": {
"node": ">=6.12"
},
@@ -54,7 +54,7 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
@@ -81,7 +81,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/utils": "^6.2.0",
"@0x/web3-wrapper": "^7.4.1",
"lodash": "^4.17.11"

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "3.3.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "3.3.2",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.3.3 - _February 10, 2021_
* Dependencies updated
## v3.3.2 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "3.3.2",
"version": "3.3.3",
"engines": {
"node": ">=6.12"
},
@@ -53,8 +53,8 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "3.1.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "3.1.23",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.24 - _February 10, 2021_
* Dependencies updated
## v3.1.23 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc721",
"version": "3.1.23",
"version": "3.1.24",
"engines": {
"node": ">=6.12"
},
@@ -54,8 +54,8 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "4.2.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "4.2.24",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.2.25 - _February 10, 2021_
* Dependencies updated
## v4.2.24 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-forwarder",
"version": "4.2.24",
"version": "4.2.25",
"engines": {
"node": ">=6.12"
},
@@ -53,18 +53,18 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-dev-utils": "^1.3.22",
"@0x/contracts-erc1155": "^2.1.23",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-erc721": "^3.1.23",
"@0x/contracts-exchange": "^3.2.24",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "4.3.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "4.3.23",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.3.24 - _February 10, 2021_
* Dependencies updated
## v4.3.23 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-libs",
"version": "4.3.23",
"version": "4.3.24",
"engines": {
"node": ">=6.12"
},
@@ -81,9 +81,9 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/order-utils": "^10.4.15",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/order-utils": "^10.4.16",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "3.2.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "3.2.24",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.25 - _February 10, 2021_
* Dependencies updated
## v3.2.24 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange",
"version": "3.2.24",
"version": "3.2.25",
"engines": {
"node": ">=6.12"
},
@@ -53,13 +53,13 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-multisig": "^4.1.24",
"@0x/contracts-staking": "^2.0.31",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-multisig": "^4.1.25",
"@0x/contracts-staking": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
@@ -89,11 +89,11 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-dev-utils": "^1.3.22",
"@0x/contracts-erc1155": "^2.1.23",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-erc721": "^3.1.23",
"@0x/order-utils": "^10.4.15",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/order-utils": "^10.4.16",
"@0x/utils": "^6.2.0",
"lodash": "^4.17.11"
},

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "6.2.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "6.2.18",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v6.2.19 - _February 10, 2021_
* Dependencies updated
## v6.2.18 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-extensions",
"version": "6.2.18",
"version": "6.2.19",
"engines": {
"node": ">=6.12"
},
@@ -53,16 +53,16 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-dev-utils": "^1.3.22",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-erc721": "^3.1.23",
"@0x/contracts-exchange": "^3.2.24",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -91,7 +91,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/typescript-typings": "^5.1.6",
"ethereum-types": "^3.4.0"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-integrations",
"version": "2.7.25",
"version": "2.7.26",
"private": true,
"engines": {
"node": ">=6.12"
@@ -53,21 +53,21 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contract-addresses": "^5.9.0",
"@0x/contract-wrappers": "^13.12.2",
"@0x/contracts-broker": "^1.1.23",
"@0x/contracts-coordinator": "^3.1.24",
"@0x/contracts-dev-utils": "^1.3.22",
"@0x/contracts-exchange-forwarder": "^4.2.24",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/contracts-extensions": "^6.2.18",
"@0x/contract-addresses": "^5.10.0",
"@0x/contract-wrappers": "^13.12.3",
"@0x/contracts-broker": "^1.1.24",
"@0x/contracts-coordinator": "^3.1.25",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-exchange-forwarder": "^4.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-extensions": "^6.2.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-utils": "^4.7.3",
"@0x/coordinator-server": "^1.0.5",
"@0x/dev-utils": "^4.2.1",
"@0x/migrations": "^6.5.11",
"@0x/order-utils": "^10.4.15",
"@0x/protocol-utils": "^1.1.5",
"@0x/migrations": "^6.6.0",
"@0x/order-utils": "^10.4.16",
"@0x/protocol-utils": "^1.2.0",
"@0x/sol-compiler": "^4.5.2",
"@0x/tslint-config": "^4.1.3",
"@0x/web3-wrapper": "^7.4.1",
@@ -93,17 +93,17 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/asset-swapper": "^5.8.2",
"@0x/asset-swapper": "^6.0.0",
"@0x/base-contract": "^6.2.18",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-erc1155": "^2.1.23",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-erc721": "^3.1.23",
"@0x/contracts-exchange": "^3.2.24",
"@0x/contracts-multisig": "^4.1.24",
"@0x/contracts-staking": "^2.0.31",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-zero-ex": "^0.18.1",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-multisig": "^4.1.25",
"@0x/contracts-staking": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-zero-ex": "^0.18.2",
"@0x/subproviders": "^6.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -1,239 +0,0 @@
import { MarketBuySwapQuote, MarketSellSwapQuote, Orderbook, SwapQuoter } from '@0x/asset-swapper';
import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils';
import { assetDataUtils } from '@0x/order-utils';
import { FillResults, SignedOrder } from '@0x/types';
import { BigNumber, logUtils } from '@0x/utils';
import * as _ from 'lodash';
import { TestMainnetAggregatorFillsContract } from '../wrappers';
import { tokens } from './tokens';
blockchainTests.live('Aggregator Mainnet Tests', env => {
// Mainnet address of the `TestMainnetAggregatorFills` contract.
const TEST_CONTRACT_ADDRESS = '0x37Ca306F42748b7fe105F89FCBb2CD03D27c8146';
const TAKER_ADDRESS = '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B'; // Vitalik
const ORDERBOOK_POLLING_MS = 1000;
const GAS_PRICE = new BigNumber(1);
const TAKER_ASSET_ETH_VALUE = 500e18;
const MIN_BALANCE = 500.1e18;
const SYMBOLS = ['ETH', 'DAI', 'USDC', 'FOAM'];
const TEST_PAIRS = _.flatten(SYMBOLS.map(m => SYMBOLS.filter(t => t !== m).map(t => [m, t])));
const FILL_VALUES = [1, 10, 1e2, 1e3, 1e4, 2.5e4, 5e4];
let testContract: TestMainnetAggregatorFillsContract;
let swapQuoter: SwapQuoter;
let takerEthBalance: BigNumber;
const orderbooks: { [name: string]: Orderbook } = {};
async function getTakerOrdersAsync(takerAssetSymbol: string): Promise<SignedOrder[]> {
if (takerAssetSymbol === 'ETH') {
return [];
}
return getOrdersAsync(takerAssetSymbol, 'ETH');
}
// Fetches ETH -> taker asset orders for the forwarder contract.
async function getOrdersAsync(makerAssetSymbol: string, takerAssetSymbol: string): Promise<SignedOrder[]> {
const takerTokenAddress = tokens[takerAssetSymbol].address;
const makerTokenAddress = tokens[makerAssetSymbol].address;
const makerAssetData = assetDataUtils.encodeERC20AssetData(makerTokenAddress);
const takerAssetData = assetDataUtils.encodeERC20AssetData(takerTokenAddress);
const orders = _.flatten(
await Promise.all(
Object.keys(orderbooks).map(async name =>
getOrdersFromOrderBookAsync(name, makerAssetData, takerAssetData),
),
),
);
const uniqueOrders: SignedOrder[] = [];
for (const order of orders) {
if (!order.makerFee.eq(0) || !order.takerFee.eq(0)) {
continue;
}
if (uniqueOrders.findIndex(o => isSameOrder(order, o)) === -1) {
uniqueOrders.push(order);
}
}
return uniqueOrders;
}
async function getOrdersFromOrderBookAsync(
name: string,
makerAssetData: string,
takerAssetData: string,
): Promise<SignedOrder[]> {
try {
return (await orderbooks[name].getOrdersAsync(makerAssetData, takerAssetData)).map(r => r.order);
} catch (err) {
logUtils.warn(`Failed to retrieve orders from orderbook "${name}".`);
}
return [];
}
function isSameOrder(a: SignedOrder, b: SignedOrder): boolean {
for (const [k, v] of Object.entries(a)) {
if (k in (b as any)) {
if (BigNumber.isBigNumber(v) && !v.eq((b as any)[k])) {
return false;
}
if (v !== (b as any)[k]) {
return false;
}
}
}
return true;
}
function toTokenUnits(symbol: string, weis: Numberish): BigNumber {
return new BigNumber(weis).div(new BigNumber(10).pow(tokens[symbol].decimals));
}
function fromTokenUnits(symbol: string, units: Numberish): BigNumber {
return new BigNumber(units)
.times(new BigNumber(10).pow(tokens[symbol].decimals))
.integerValue(BigNumber.ROUND_DOWN);
}
interface MarketOperationResult {
makerAssetBalanceBefore: BigNumber;
takerAssetBalanceBefore: BigNumber;
makerAssetBalanceAfter: BigNumber;
takerAssetBalanceAfter: BigNumber;
fillResults: FillResults;
}
// Liquidity is low right now so it's possible we didn't have
// enough taker assets to cover the orders, so occasionally we'll get incomplete
// fills. This function will catch those cases.
// TODO(dorothy-zbornak): Remove this special case when liquidity is up.
function checkHadEnoughTakerAsset(
quote: MarketBuySwapQuote | MarketSellSwapQuote,
result: MarketOperationResult,
): boolean {
if (result.takerAssetBalanceBefore.gte(quote.worstCaseQuoteInfo.takerAssetAmount)) {
return true;
}
const takerAssetPct = result.takerAssetBalanceBefore
.div(quote.worstCaseQuoteInfo.takerAssetAmount)
.times(100)
.toNumber()
.toFixed(1);
logUtils.warn(`Could not acquire enough taker asset to complete the fill: ${takerAssetPct}%`);
expect(result.fillResults.makerAssetFilledAmount).to.bignumber.lt(quote.worstCaseQuoteInfo.makerAssetAmount);
return false;
}
before(async () => {
testContract = new TestMainnetAggregatorFillsContract(TEST_CONTRACT_ADDRESS, env.provider, {
...env.txDefaults,
gasPrice: GAS_PRICE,
gas: 10e6,
});
swapQuoter = SwapQuoter.getSwapQuoterForStandardRelayerAPIUrl(env.provider, 'https://api.0x.org/sra');
// Pool orderbooks because we're desperate for liquidity.
orderbooks.swapQuoter = swapQuoter.orderbook;
orderbooks.bamboo = Orderbook.getOrderbookForPollingProvider({
httpEndpoint: 'https://sra.bamboorelay.com/0x/v3',
pollingIntervalMs: ORDERBOOK_POLLING_MS,
});
// TODO(dorothy-zbornak): Uncomment when radar's SRA is up.
// orderbooks.radar = Orderbook.getOrderbookForPollingProvider({
// httpEndpoint: 'https://api-v3.radarrelay.com/v3',
// pollingIntervalMs: ORDERBOOK_POLLING_MS,
// });
takerEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(TAKER_ADDRESS);
});
it('taker has minimum ETH', async () => {
expect(takerEthBalance).to.bignumber.gte(MIN_BALANCE);
});
describe('market sells', () => {
for (const [makerSymbol, takerSymbol] of TEST_PAIRS) {
for (const fillValue of FILL_VALUES) {
const fillAmount = fromTokenUnits(takerSymbol, new BigNumber(fillValue).div(tokens[takerSymbol].price));
it(`sell ${toTokenUnits(takerSymbol, fillAmount)} ${takerSymbol} for ${makerSymbol}`, async () => {
const [quote, takerOrders] = await Promise.all([
swapQuoter.getMarketSellSwapQuoteAsync(
tokens[makerSymbol].address,
tokens[takerSymbol].address,
fillAmount,
{ gasPrice: GAS_PRICE },
),
getTakerOrdersAsync(takerSymbol),
]);
// Buy taker assets from `takerOrders` and and perform a
// market sell on the bridge orders.
const fill = await testContract
.marketSell(
tokens[makerSymbol].address,
tokens[takerSymbol].address,
quote.orders,
takerOrders,
quote.orders.map(o => o.signature),
takerOrders.map(o => o.signature),
quote.takerAssetFillAmount,
)
.callAsync({
value: quote.worstCaseQuoteInfo.protocolFeeInWeiAmount.plus(TAKER_ASSET_ETH_VALUE),
from: TAKER_ADDRESS,
gasPrice: quote.gasPrice,
});
if (checkHadEnoughTakerAsset(quote, fill)) {
expect(fill.fillResults.makerAssetFilledAmount, 'makerAssetFilledAmount').to.bignumber.gte(
quote.worstCaseQuoteInfo.makerAssetAmount,
);
expect(fill.fillResults.takerAssetFilledAmount, 'takerAssetFilledAmount').to.bignumber.lte(
quote.takerAssetFillAmount,
);
}
});
}
}
});
describe('market buys', () => {
for (const [makerSymbol, takerSymbol] of TEST_PAIRS) {
for (const fillValue of FILL_VALUES) {
const fillAmount = fromTokenUnits(makerSymbol, new BigNumber(fillValue).div(tokens[makerSymbol].price));
it(`buy ${toTokenUnits(makerSymbol, fillAmount)} ${makerSymbol} with ${takerSymbol}`, async () => {
const [quote, takerOrders] = await Promise.all([
swapQuoter.getMarketBuySwapQuoteAsync(
tokens[makerSymbol].address,
tokens[takerSymbol].address,
fillAmount,
{ gasPrice: GAS_PRICE },
),
getTakerOrdersAsync(takerSymbol),
]);
// Buy taker assets from `takerOrders` and and perform a
// market buy on the bridge orders.
const fill = await testContract
.marketBuy(
tokens[makerSymbol].address,
tokens[takerSymbol].address,
quote.orders,
takerOrders,
quote.orders.map(o => o.signature),
takerOrders.map(o => o.signature),
quote.makerAssetFillAmount,
)
.callAsync({
value: quote.worstCaseQuoteInfo.protocolFeeInWeiAmount.plus(TAKER_ASSET_ETH_VALUE),
from: TAKER_ADDRESS,
gasPrice: quote.gasPrice,
});
if (checkHadEnoughTakerAsset(quote, fill)) {
expect(fill.fillResults.takerAssetFilledAmount, 'takerAssetFilledAmount').to.bignumber.lte(
quote.worstCaseQuoteInfo.takerAssetAmount,
);
expect(fill.fillResults.makerAssetFilledAmount, 'makerAssetFilledAmount').to.bignumber.gte(
quote.makerAssetFillAmount,
);
}
});
}
}
});
});

View File

@@ -1,77 +0,0 @@
export const tokens: { [symbol: string]: { address: string; decimals: number; price: number } } = {
ETH: {
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
decimals: 18,
price: 133,
},
SAI: {
address: '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359',
decimals: 18,
price: 1,
},
DAI: {
address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
decimals: 18,
price: 1,
},
USDC: {
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
decimals: 6,
price: 1,
},
WBTC: {
address: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
decimals: 8,
price: 6900,
},
MKR: {
address: '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2',
decimals: 18,
price: 454,
},
BAT: {
address: '0x0D8775F648430679A709E98d2b0Cb6250d2887EF',
decimals: 18,
price: 0.17,
},
OMG: {
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
decimals: 18,
price: 0.65,
},
ZRX: {
address: '0xE41d2489571d322189246DaFA5ebDe1F4699F498',
decimals: 18,
price: 0.19,
},
ZIL: {
address: '0x05f4a42e251f2d52b8ed15E9FEdAacFcEF1FAD27',
decimals: 12,
price: 0.004,
},
FOAM: {
address: '0x4946Fcea7C692606e8908002e55A582af44AC121',
decimals: 18,
price: 0.004,
},
USDT: {
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
decimals: 6,
price: 0.019,
},
REP: {
address: '0x1985365e9f78359a9B6AD760e32412f4a445E862',
decimals: 18,
price: 8.9,
},
MANA: {
address: '0x0F5D2fB29fb7d3CFeE444a200298f468908cC942',
decimals: 18,
price: 0.025,
},
LINK: {
address: '0x514910771AF9Ca656af840dff83E8264EcF986CA',
decimals: 18,
price: 1.8,
},
};

View File

@@ -1,360 +0,0 @@
import { ContractAddresses } from '@0x/contract-addresses';
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
import { IExchangeContract } from '@0x/contracts-exchange';
import { blockchainTests, constants, expect, getRandomPortion, verifyEventsFromLogs } from '@0x/contracts-test-utils';
import {
artifacts as exchangeProxyArtifacts,
IZeroExContract,
LogMetadataTransformerContract,
} from '@0x/contracts-zero-ex';
import { migrateOnceAsync } from '@0x/migrations';
import { assetDataUtils, signatureUtils, SignedExchangeProxyMetaTransaction } from '@0x/order-utils';
import {
encodeFillQuoteTransformerData,
encodePayTakerTransformerData,
ETH_TOKEN_ADDRESS,
FillQuoteTransformerSide,
findTransformerNonce,
Signature,
} from '@0x/protocol-utils';
import { AssetProxyId, Order, SignedOrder } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import * as ethjs from 'ethereumjs-util';
const { MAX_UINT256, NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
function sigstruct(signature: string): Signature {
return {
v: parseInt(hexUtils.slice(signature, 0, 1), 16),
signatureType: parseInt(hexUtils.slice(signature, 65, 66), 16),
r: hexUtils.slice(signature, 1, 33),
s: hexUtils.slice(signature, 33, 65),
};
}
blockchainTests.resets('exchange proxy - meta-transactions', env => {
const quoteSignerKey = hexUtils.random();
const quoteSigner = hexUtils.toHex(ethjs.privateToAddress(ethjs.toBuffer(quoteSignerKey)));
let owner: string;
let relayer: string;
let maker: string;
let taker: string;
let flashWalletAddress: string;
let zeroEx: IZeroExContract;
let exchange: IExchangeContract;
let inputToken: DummyERC20TokenContract;
let outputToken: DummyERC20TokenContract;
let feeToken: DummyERC20TokenContract;
let addresses: ContractAddresses;
let protocolFee: BigNumber;
let metadataTransformer: LogMetadataTransformerContract;
const GAS_PRICE = new BigNumber('1e9');
const MAKER_BALANCE = new BigNumber('100e18');
const TAKER_BALANCE = new BigNumber('100e18');
const TAKER_FEE_BALANCE = new BigNumber('100e18');
before(async () => {
[, relayer, maker, taker] = await env.getAccountAddressesAsync();
addresses = await migrateOnceAsync(env.provider);
zeroEx = new IZeroExContract(addresses.exchangeProxy, env.provider, env.txDefaults, {
LogMetadataTransformer: LogMetadataTransformerContract.ABI(),
DummyERC20Token: DummyERC20TokenContract.ABI(),
});
exchange = new IExchangeContract(addresses.exchange, env.provider, env.txDefaults);
[inputToken, outputToken, feeToken] = await Promise.all(
[...new Array(3)].map(i =>
DummyERC20TokenContract.deployFrom0xArtifactAsync(
erc20Artifacts.DummyERC20Token,
env.provider,
env.txDefaults,
{},
`DummyToken-${i}`,
`TOK${i}`,
new BigNumber(18),
BigNumber.max(MAKER_BALANCE, TAKER_BALANCE),
),
),
);
// LogMetadataTransformer is not deployed in migrations.
metadataTransformer = await LogMetadataTransformerContract.deployFrom0xArtifactAsync(
exchangeProxyArtifacts.LogMetadataTransformer,
env.provider,
{
...env.txDefaults,
from: addresses.exchangeProxyTransformerDeployer,
},
{},
);
owner = await zeroEx.owner().callAsync();
protocolFee = await exchange.protocolFeeMultiplier().callAsync();
flashWalletAddress = await zeroEx.getTransformWallet().callAsync();
const erc20Proxy = await exchange.getAssetProxy(AssetProxyId.ERC20).callAsync();
const allowanceTarget = await zeroEx.getAllowanceTarget().callAsync();
await outputToken.mint(MAKER_BALANCE).awaitTransactionSuccessAsync({ from: maker });
await inputToken.mint(TAKER_BALANCE).awaitTransactionSuccessAsync({ from: taker });
await feeToken.mint(TAKER_FEE_BALANCE).awaitTransactionSuccessAsync({ from: taker });
await outputToken.approve(erc20Proxy, MAX_UINT256).awaitTransactionSuccessAsync({ from: maker });
await inputToken.approve(allowanceTarget, MAX_UINT256).awaitTransactionSuccessAsync({ from: taker });
await feeToken.approve(allowanceTarget, MAX_UINT256).awaitTransactionSuccessAsync({ from: taker });
await zeroEx.setQuoteSigner(quoteSigner).awaitTransactionSuccessAsync({ from: owner });
});
interface Transformation {
deploymentNonce: number;
data: string;
}
interface SwapInfo {
inputTokenAddress: string;
outputTokenAddress: string;
inputTokenAmount: BigNumber;
minOutputTokenAmount: BigNumber;
transformations: Transformation[];
orders: SignedOrder[];
}
async function generateSwapAsync(orderFields: Partial<Order> = {}, isRfqt: boolean = false): Promise<SwapInfo> {
const order = await signatureUtils.ecSignTypedDataOrderAsync(
env.provider,
{
chainId: 1337,
exchangeAddress: exchange.address,
expirationTimeSeconds: new BigNumber(Date.now()),
salt: new BigNumber(hexUtils.random()),
feeRecipientAddress: NULL_ADDRESS,
senderAddress: NULL_ADDRESS,
takerAddress: isRfqt ? flashWalletAddress : NULL_ADDRESS,
makerAddress: maker,
makerAssetData: assetDataUtils.encodeERC20AssetData(outputToken.address),
takerAssetData: assetDataUtils.encodeERC20AssetData(inputToken.address),
makerFeeAssetData: NULL_BYTES,
takerFeeAssetData: NULL_BYTES,
takerAssetAmount: getRandomPortion(TAKER_BALANCE),
makerAssetAmount: getRandomPortion(MAKER_BALANCE),
makerFee: ZERO_AMOUNT,
takerFee: ZERO_AMOUNT,
...orderFields,
},
maker,
);
const transformations = [
{
deploymentNonce: findTransformerNonce(
addresses.transformers.fillQuoteTransformer,
addresses.exchangeProxyTransformerDeployer,
),
data: encodeFillQuoteTransformerData({
orders: [order],
signatures: [order.signature],
buyToken: outputToken.address,
sellToken: inputToken.address,
fillAmount: order.takerAssetAmount,
maxOrderFillAmounts: [],
refundReceiver: hexUtils.leftPad(2, 20), // Send refund to sender.
rfqtTakerAddress: isRfqt ? taker : NULL_ADDRESS,
side: FillQuoteTransformerSide.Sell,
}),
},
{
deploymentNonce: findTransformerNonce(
addresses.transformers.payTakerTransformer,
addresses.exchangeProxyTransformerDeployer,
),
data: encodePayTakerTransformerData({
tokens: [inputToken.address, outputToken.address, ETH_TOKEN_ADDRESS],
amounts: [MAX_UINT256, MAX_UINT256, MAX_UINT256],
}),
},
{
deploymentNonce: findTransformerNonce(
metadataTransformer.address,
addresses.exchangeProxyTransformerDeployer,
),
data: NULL_BYTES,
},
];
return {
transformations,
orders: [order],
inputTokenAddress: inputToken.address,
outputTokenAddress: outputToken.address,
inputTokenAmount: order.takerAssetAmount,
minOutputTokenAmount: order.makerAssetAmount,
};
}
function getSwapData(swap: SwapInfo): string {
return zeroEx
.transformERC20(
swap.inputTokenAddress,
swap.outputTokenAddress,
swap.inputTokenAmount,
swap.minOutputTokenAmount,
swap.transformations,
)
.getABIEncodedTransactionData();
}
async function createMetaTransactionAsync(
data: string,
value: BigNumber,
fee?: BigNumber | number,
): Promise<SignedExchangeProxyMetaTransaction> {
return signatureUtils.ecSignTypedDataExchangeProxyMetaTransactionAsync(
env.provider,
{
value,
signer: taker,
sender: relayer,
minGasPrice: GAS_PRICE,
maxGasPrice: GAS_PRICE,
expirationTimeSeconds: new BigNumber(Math.floor(Date.now() / 1000) + 60),
salt: new BigNumber(hexUtils.random()),
callData: data,
feeToken: feeToken.address,
feeAmount: fee !== undefined ? new BigNumber(fee) : getRandomPortion(TAKER_FEE_BALANCE),
domain: {
chainId: 1,
name: 'ZeroEx',
version: '1.0.0',
verifyingContract: zeroEx.address,
},
},
taker,
);
}
it('can call `transformERC20()` with calldata and no relayer fee', async () => {
const swap = await generateSwapAsync();
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee, 0);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
.awaitTransactionSuccessAsync({ from: relayer, value: mtx.value, gasPrice: GAS_PRICE });
const relayerEthRefund = relayerEthBalanceBefore
.minus(await env.web3Wrapper.getBalanceInWeiAsync(relayer))
.minus(GAS_PRICE.times(receipt.gasUsed));
// Ensure the relayer got back the unused protocol fees.
expect(relayerEthRefund).to.bignumber.eq(protocolFee.times(GAS_PRICE));
// Ensure the relayer got paid no mtx fees.
expect(await feeToken.balanceOf(relayer).callAsync()).to.bignumber.eq(0);
// Ensure the taker got output tokens.
expect(await outputToken.balanceOf(taker).callAsync()).to.bignumber.eq(swap.minOutputTokenAmount);
// Ensure the maker got input tokens.
expect(await inputToken.balanceOf(maker).callAsync()).to.bignumber.eq(swap.inputTokenAmount);
// Check events.
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
sender: zeroEx.address,
data: NULL_BYTES,
},
],
'TransformerMetadata',
);
});
it('can call `transformERC20()` with calldata and a relayer fee', async () => {
const swap = await generateSwapAsync();
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
.awaitTransactionSuccessAsync({ from: relayer, value: mtx.value, gasPrice: GAS_PRICE });
const relayerEthRefund = relayerEthBalanceBefore
.minus(await env.web3Wrapper.getBalanceInWeiAsync(relayer))
.minus(GAS_PRICE.times(receipt.gasUsed));
// Ensure the relayer got back the unused protocol fees.
expect(relayerEthRefund).to.bignumber.eq(protocolFee.times(GAS_PRICE));
// Ensure the relayer got paid mtx fees.
expect(await feeToken.balanceOf(relayer).callAsync()).to.bignumber.eq(mtx.feeAmount);
// Ensure the taker got output tokens.
expect(await outputToken.balanceOf(taker).callAsync()).to.bignumber.eq(swap.minOutputTokenAmount);
// Ensure the maker got input tokens.
expect(await inputToken.balanceOf(maker).callAsync()).to.bignumber.eq(swap.inputTokenAmount);
// Check events.
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
sender: zeroEx.address,
data: NULL_BYTES,
},
],
'TransformerMetadata',
);
});
it('`transformERC20()` can fill RFQT order', async () => {
const swap = await generateSwapAsync({}, true);
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee, 0);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
.awaitTransactionSuccessAsync({ from: relayer, value: mtx.value, gasPrice: GAS_PRICE });
const relayerEthRefund = relayerEthBalanceBefore
.minus(await env.web3Wrapper.getBalanceInWeiAsync(relayer))
.minus(GAS_PRICE.times(receipt.gasUsed));
// Ensure the relayer got back the unused protocol fees.
expect(relayerEthRefund).to.bignumber.eq(protocolFee.times(GAS_PRICE));
// Ensure the relayer got paid no mtx fees.
expect(await feeToken.balanceOf(relayer).callAsync()).to.bignumber.eq(0);
// Ensure the taker got output tokens.
expect(await outputToken.balanceOf(taker).callAsync()).to.bignumber.eq(swap.minOutputTokenAmount);
// Ensure the maker got input tokens.
expect(await inputToken.balanceOf(maker).callAsync()).to.bignumber.eq(swap.inputTokenAmount);
// Check events.
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
sender: zeroEx.address,
data: NULL_BYTES,
},
],
'TransformerMetadata',
);
});
it('`transformERC20()` can fill RFQT order if quote signer configured', async () => {
const swap = await generateSwapAsync({}, true);
const callData = getSwapData(swap);
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(callData, _protocolFee, 0);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
await zeroEx.setQuoteSigner(NULL_ADDRESS).awaitTransactionSuccessAsync({ from: owner });
const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
.awaitTransactionSuccessAsync({ from: relayer, value: mtx.value, gasPrice: GAS_PRICE });
const relayerEthRefund = relayerEthBalanceBefore
.minus(await env.web3Wrapper.getBalanceInWeiAsync(relayer))
.minus(GAS_PRICE.times(receipt.gasUsed));
// Ensure the relayer got back the unused protocol fees.
expect(relayerEthRefund).to.bignumber.eq(protocolFee.times(GAS_PRICE));
// Ensure the relayer got paid no mtx fees.
expect(await feeToken.balanceOf(relayer).callAsync()).to.bignumber.eq(0);
// Ensure the taker got output tokens.
expect(await outputToken.balanceOf(taker).callAsync()).to.bignumber.eq(swap.minOutputTokenAmount);
// Ensure the maker got input tokens.
expect(await inputToken.balanceOf(maker).callAsync()).to.bignumber.eq(swap.inputTokenAmount);
// Check events.
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
sender: zeroEx.address,
data: NULL_BYTES,
},
],
'TransformerMetadata',
);
});
});

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "4.1.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "4.1.24",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.1.25 - _February 10, 2021_
* Dependencies updated
## v4.1.24 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-multisig",
"version": "4.1.24",
"version": "4.1.25",
"engines": {
"node": ">=6.12"
},
@@ -50,11 +50,11 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "2.0.32",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "2.0.31",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.32 - _February 10, 2021_
* Dependencies updated
## v2.0.31 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-staking",
"version": "2.0.31",
"version": "2.0.32",
"engines": {
"node": ">=6.12"
},
@@ -54,14 +54,14 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-dev-utils": "^1.3.22",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-utils": "^4.7.3",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -88,7 +88,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",
"ethereum-types": "^3.4.0",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "5.3.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "5.3.20",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.3.21 - _February 10, 2021_
* Dependencies updated
## v5.3.20 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-test-utils",
"version": "5.3.20",
"version": "5.3.21",
"engines": {
"node": ">=6.12"
},
@@ -44,10 +44,10 @@
"dependencies": {
"@0x/assert": "^3.0.21",
"@0x/base-contract": "^6.2.18",
"@0x/contract-addresses": "^5.9.0",
"@0x/contract-addresses": "^5.10.0",
"@0x/dev-utils": "^4.2.1",
"@0x/json-schemas": "^5.4.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/sol-coverage": "^4.0.29",
"@0x/sol-profiler": "^4.1.19",
"@0x/sol-trace": "^3.0.29",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0",
"changes": [

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.1 - _February 10, 2021_
* Dependencies updated
## v1.0.0 - _January 28, 2021_
* Create this package (#120)

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-treasury",
"version": "1.0.0",
"version": "1.0.1",
"engines": {
"node": ">=6.12"
},
@@ -47,12 +47,12 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contract-addresses": "^5.8.0",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contract-addresses": "^5.10.0",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-staking": "^2.0.29",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-staking": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -73,7 +73,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/protocol-utils": "^1.1.3",
"@0x/protocol-utils": "^1.2.0",
"@0x/subproviders": "^6.2.3",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1612950500,
"version": "4.7.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "4.7.2",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.7.3 - _February 10, 2021_
* Dependencies updated
## v4.7.2 - _January 26, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-utils",
"version": "4.7.2",
"version": "4.7.3",
"engines": {
"node": ">=6.12"
},
@@ -52,9 +52,9 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",

View File

@@ -1,4 +1,14 @@
[
{
"version": "0.18.2",
"changes": [
{
"note": "Update FQT for v4 native orders",
"pr": 104
}
],
"timestamp": 1612950500
},
{
"version": "0.18.1",
"changes": [

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v0.18.2 - _February 10, 2021_
* Update FQT for v4 native orders (#104)
## v0.18.1 - _January 26, 2021_
* Swallow reverts in `batchGetLimitOrderRelevantStates()` and `batchGetRfqOrderRelevantStates()` (#117)

View File

@@ -22,13 +22,12 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../errors/LibTransformERC20RichErrors.sol";
import "../vendor/v3/IExchange.sol";
import "../vendor/v3/LibOrderHash.sol";
import "../features/INativeOrdersFeature.sol";
import "../features/libs/LibNativeOrder.sol";
import "./bridges/IBridgeAdapter.sol";
import "./Transformer.sol";
import "./LibERC20Transformer.sol";
@@ -41,8 +40,8 @@ contract FillQuoteTransformer is
using LibERC20TokenV06 for IERC20TokenV06;
using LibERC20Transformer for IERC20TokenV06;
using LibSafeMathV06 for uint256;
using LibSafeMathV06 for uint128;
using LibRichErrorsV06 for bytes;
using LibBytesV06 for bytes;
/// @dev Whether we are performing a market sell or buy.
enum Side {
@@ -50,6 +49,26 @@ contract FillQuoteTransformer is
Buy
}
enum OrderType {
Bridge,
Limit,
Rfq
}
struct LimitOrderInfo {
LibNativeOrder.LimitOrder order;
LibSignature.Signature signature;
// Maximum taker token amount of this limit order to fill.
uint256 maxTakerTokenFillAmount;
}
struct RfqOrderInfo {
LibNativeOrder.RfqOrder order;
LibSignature.Signature signature;
// Maximum taker token amount of this limit order to fill.
uint256 maxTakerTokenFillAmount;
}
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// Whether we are performing a market sell or buy.
@@ -60,31 +79,34 @@ contract FillQuoteTransformer is
// The token being bought.
// This should be an actual token, not the ETH pseudo-token.
IERC20TokenV06 buyToken;
// The orders to fill.
IExchange.Order[] orders;
// Signatures for each respective order in `orders`.
bytes[] signatures;
// Maximum fill amount for each order. This may be shorter than the
// number of orders, where missing entries will be treated as `uint256(-1)`.
// For sells, this will be the maximum sell amount (taker asset).
// For buys, this will be the maximum buy amount (maker asset).
uint256[] maxOrderFillAmounts;
// External liquidity bridge orders. Sorted by fill sequence.
IBridgeAdapter.BridgeOrder[] bridgeOrders;
// Native limit orders. Sorted by fill sequence.
LimitOrderInfo[] limitOrders;
// Native RFQ orders. Sorted by fill sequence.
RfqOrderInfo[] rfqOrders;
// The sequence to fill the orders in. Each item will fill the next
// order of that type in either `bridgeOrders`, `limitOrders`,
// or `rfqOrders.`
OrderType[] fillSequence;
// Amount of `sellToken` to sell or `buyToken` to buy.
// For sells, this may be `uint256(-1)` to sell the entire balance of
// `sellToken`.
// For sells, setting the high-bit indicates that
// `sellAmount & LOW_BITS` should be treated as a `1e18` fraction of
// the current balance of `sellToken`, where
// `1e18+ == 100%` and `0.5e18 == 50%`, etc.
uint256 fillAmount;
// Who to transfer unused protocol fees to.
// May be a valid address or one of:
// `address(0)`: Stay in flash wallet.
// `address(1)`: Send to the taker.
// `address(2)`: Send to the sender (caller of `transformERC20()`).
address payable refundReceiver;
// Required taker address for RFQT orders.
// Null means any taker can fill it.
address rfqtTakerAddress;
}
/// @dev Results of a call to `_fillOrder()`.
struct FillOrderResults {
// The amount of taker tokens sold, according to balance checks.
uint256 takerTokenSoldAmount;
@@ -101,7 +123,8 @@ contract FillQuoteTransformer is
uint256 soldAmount;
uint256 protocolFee;
uint256 takerTokenBalanceRemaining;
bool isRfqtAllowed;
uint256[3] currentIndices;
OrderType currentOrderType;
}
/// @dev Emitted when a trade is skipped due to a lack of funds
@@ -109,12 +132,12 @@ contract FillQuoteTransformer is
/// @param orderHash The hash of the order that was skipped.
event ProtocolFeeUnfunded(bytes32 orderHash);
/// @dev The Exchange ERC20Proxy ID.
bytes4 private constant ERC20_ASSET_PROXY_ID = 0xf47261b0;
/// @dev The Exchange ERC20BridgeProxy ID.
bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
/// @dev Maximum uint256 value.
uint256 private constant MAX_UINT256 = uint256(-1);
/// @dev The highest bit of a uint256 value.
uint256 private constant HIGH_BIT = 2 ** 255;
/// @dev Mask of the lower 255 bits of a uint256 value.
uint256 private constant LOWER_255_BITS = HIGH_BIT - 1;
/// @dev If `refundReceiver` is set to this address, unpsent
/// protocol fees will be sent to the taker.
address private constant REFUND_RECEIVER_TAKER = address(1);
@@ -122,33 +145,32 @@ contract FillQuoteTransformer is
/// protocol fees will be sent to the sender.
address private constant REFUND_RECEIVER_SENDER = address(2);
/// @dev The Exchange contract.
IExchange public immutable exchange;
/// @dev The ERC20Proxy address.
address public immutable erc20Proxy;
/// @dev The BridgeAdapter address
IBridgeAdapter public immutable bridgeAdapter;
/// @dev The exchange proxy contract.
INativeOrdersFeature public immutable zeroEx;
/// @dev Create this contract.
/// @param exchange_ The Exchange V3 instance.
constructor(IExchange exchange_, IBridgeAdapter bridgeAdapter_)
/// @param bridgeAdapter_ The bridge adapter contract.
/// @param zeroEx_ The Exchange Proxy contract.
constructor(IBridgeAdapter bridgeAdapter_, INativeOrdersFeature zeroEx_)
public
Transformer()
{
exchange = exchange_;
erc20Proxy = exchange_.getAssetProxy(ERC20_ASSET_PROXY_ID);
bridgeAdapter = bridgeAdapter_;
zeroEx = zeroEx_;
}
/// @dev Sell this contract's entire balance of of `sellToken` in exchange
/// for `buyToken` by filling `orders`. Protocol fees should be attached
/// to this call. `buyToken` and excess ETH will be transferred back to the caller.
/// @param context Context information.
/// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`).
/// @return magicBytes The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`).
function transform(TransformContext calldata context)
external
override
returns (bytes4 success)
returns (bytes4 magicBytes)
{
TransformData memory data = abi.decode(context.data, (TransformData));
FillState memory state;
@@ -160,7 +182,11 @@ contract FillQuoteTransformer is
context.data
).rrevert();
}
if (data.orders.length != data.signatures.length) {
if (data.bridgeOrders.length
+ data.limitOrders.length
+ data.rfqOrders.length != data.fillSequence.length
) {
LibTransformERC20RichErrors.InvalidTransformDataError(
LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_ARRAY_LENGTH,
context.data
@@ -168,76 +194,58 @@ contract FillQuoteTransformer is
}
state.takerTokenBalanceRemaining = data.sellToken.getTokenBalanceOf(address(this));
if (data.side == Side.Sell && data.fillAmount == MAX_UINT256) {
// If `sellAmount == -1 then we are selling
// the entire balance of `sellToken`. This is useful in cases where
// the exact sell amount is not exactly known in advance, like when
// unwrapping Chai/cUSDC/cDAI.
data.fillAmount = state.takerTokenBalanceRemaining;
if (data.side == Side.Sell) {
data.fillAmount = _normalizeFillAmount(data.fillAmount, state.takerTokenBalanceRemaining);
}
// Approve the ERC20 proxy to spend `sellToken`.
data.sellToken.approveIfBelow(erc20Proxy, data.fillAmount);
// Approve the exchange proxy to spend our sell tokens if native orders
// are present.
if (data.limitOrders.length + data.rfqOrders.length != 0) {
data.sellToken.approveIfBelow(address(zeroEx), data.fillAmount);
// Compute the protocol fee if a limit order is present.
if (data.limitOrders.length != 0) {
state.protocolFee = uint256(zeroEx.getProtocolFeeMultiplier())
.safeMul(tx.gasprice);
}
}
state.protocolFee = exchange.protocolFeeMultiplier().safeMul(tx.gasprice);
state.ethRemaining = address(this).balance;
// RFQT orders can only be filled if the actual taker matches the RFQT
// taker (if set).
state.isRfqtAllowed = data.rfqtTakerAddress == address(0)
|| context.taker == data.rfqtTakerAddress;
// Fill the orders.
for (uint256 i = 0; i < data.orders.length; ++i) {
for (uint256 i = 0; i < data.fillSequence.length; ++i) {
// Check if we've hit our targets.
if (data.side == Side.Sell) {
// Market sell check.
if (state.soldAmount >= data.fillAmount) {
break;
}
if (state.soldAmount >= data.fillAmount) { break; }
} else {
// Market buy check.
if (state.boughtAmount >= data.fillAmount) {
break;
}
if (state.boughtAmount >= data.fillAmount) { break; }
}
state.currentOrderType = OrderType(data.fillSequence[i]);
uint256 orderIndex = state.currentIndices[uint256(state.currentOrderType)];
// Fill the order.
FillOrderResults memory results;
if (data.side == Side.Sell) {
// Market sell.
results = _sellToOrder(
data.buyToken,
data.sellToken,
data.orders[i],
data.signatures[i],
data.fillAmount.safeSub(state.soldAmount).min256(
data.maxOrderFillAmounts.length > i
? data.maxOrderFillAmounts[i]
: MAX_UINT256
),
state
);
if (state.currentOrderType == OrderType.Bridge) {
results = _fillBridgeOrder(data.bridgeOrders[orderIndex], data, state);
} else if (state.currentOrderType == OrderType.Limit) {
results = _fillLimitOrder(data.limitOrders[orderIndex], data, state);
} else if (state.currentOrderType == OrderType.Rfq) {
results = _fillRfqOrder(data.rfqOrders[orderIndex], data, state);
} else {
// Market buy.
results = _buyFromOrder(
data.buyToken,
data.sellToken,
data.orders[i],
data.signatures[i],
data.fillAmount.safeSub(state.boughtAmount).min256(
data.maxOrderFillAmounts.length > i
? data.maxOrderFillAmounts[i]
: MAX_UINT256
),
state
);
revert("INVALID_ORDER_TYPE");
}
// Accumulate totals.
state.soldAmount = state.soldAmount.safeAdd(results.takerTokenSoldAmount);
state.boughtAmount = state.boughtAmount.safeAdd(results.makerTokenBoughtAmount);
state.ethRemaining = state.ethRemaining.safeSub(results.protocolFeePaid);
state.takerTokenBalanceRemaining = state.takerTokenBalanceRemaining.safeSub(results.takerTokenSoldAmount);
state.soldAmount = state.soldAmount
.safeAdd(results.takerTokenSoldAmount);
state.boughtAmount = state.boughtAmount
.safeAdd(results.makerTokenBoughtAmount);
state.ethRemaining = state.ethRemaining
.safeSub(results.protocolFeePaid);
state.takerTokenBalanceRemaining = state.takerTokenBalanceRemaining
.safeSub(results.takerTokenSoldAmount);
state.currentIndices[uint256(state.currentOrderType)]++;
}
// Ensure we hit our targets.
@@ -276,223 +284,174 @@ contract FillQuoteTransformer is
return LibERC20Transformer.TRANSFORMER_SUCCESS;
}
/// @dev Try to sell up to `sellAmount` from an order.
/// @param makerToken The maker/buy token.
/// @param takerToken The taker/sell token.
/// @param order The order to fill.
/// @param signature The signature for `order`.
/// @param sellAmount Amount of taker token to sell.
/// @param state Intermediate state variables to get around stack limits.
function _sellToOrder(
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
IExchange.Order memory order,
bytes memory signature,
uint256 sellAmount,
// Fill a single bridge order.
function _fillBridgeOrder(
IBridgeAdapter.BridgeOrder memory order,
TransformData memory data,
FillState memory state
)
private
returns (FillOrderResults memory results)
{
IERC20TokenV06 takerFeeToken =
_getTokenFromERC20AssetData(order.takerFeeAssetData);
uint256 takerTokenFillAmount = sellAmount;
if (order.takerFee != 0) {
if (takerFeeToken == makerToken) {
// Taker fee is payable in the maker token, so we need to
// approve the proxy to spend the maker token.
// It isn't worth computing the actual taker fee
// since `approveIfBelow()` will set the allowance to infinite. We
// just need a reasonable upper bound to avoid unnecessarily re-approving.
takerFeeToken.approveIfBelow(erc20Proxy, order.takerFee);
} else if (takerFeeToken == takerToken){
// Taker fee is payable in the taker token, so we need to
// reduce the fill amount to cover the fee.
// takerTokenFillAmount' =
// (takerTokenFillAmount * order.takerAssetAmount) /
// (order.takerAssetAmount + order.takerFee)
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
order.takerAssetAmount,
order.takerAssetAmount.safeAdd(order.takerFee),
sellAmount
);
} else {
// Only support taker or maker asset denominated taker fees.
LibTransformERC20RichErrors.InvalidTakerFeeTokenError(
address(takerFeeToken)
).rrevert();
}
}
// Perform the fill.
return _fillOrder(
order,
signature,
takerTokenFillAmount,
uint256 takerTokenFillAmount = _computeTakerTokenFillAmount(
data,
state,
takerFeeToken == takerToken
order.takerTokenAmount,
order.makerTokenAmount,
0
);
(bool success, bytes memory resultData) = address(bridgeAdapter).delegatecall(
abi.encodeWithSelector(
IBridgeAdapter.trade.selector,
order,
data.sellToken,
data.buyToken,
takerTokenFillAmount
)
);
if (success) {
results.makerTokenBoughtAmount = abi.decode(resultData, (uint256));
results.takerTokenSoldAmount = takerTokenFillAmount;
}
}
/// @dev Try to buy up to `buyAmount` from an order.
/// @param makerToken The maker/buy token.
/// @param takerToken The taker/sell token.
/// @param order The order to fill.
/// @param signature The signature for `order`.
/// @param buyAmount Amount of maker token to buy.
/// @param state Intermediate state variables to get around stack limits.
function _buyFromOrder(
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
IExchange.Order memory order,
bytes memory signature,
uint256 buyAmount,
// Fill a single limit order.
function _fillLimitOrder(
LimitOrderInfo memory orderInfo,
TransformData memory data,
FillState memory state
)
private
returns (FillOrderResults memory results)
{
IERC20TokenV06 takerFeeToken =
_getTokenFromERC20AssetData(order.takerFeeAssetData);
// Compute the default taker token fill amount.
uint256 takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
buyAmount,
order.makerAssetAmount,
order.takerAssetAmount
uint256 takerTokenFillAmount = LibSafeMathV06.min256(
_computeTakerTokenFillAmount(
data,
state,
orderInfo.order.takerAmount,
orderInfo.order.makerAmount,
orderInfo.order.takerTokenFeeAmount
),
orderInfo.maxTakerTokenFillAmount
);
if (order.takerFee != 0) {
if (takerFeeToken == makerToken) {
// Taker fee is payable in the maker token.
// Adjust the taker token fill amount to account for maker
// tokens being lost to the taker fee.
// takerTokenFillAmount' =
// (order.takerAssetAmount * buyAmount) /
// (order.makerAssetAmount - order.takerFee)
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
buyAmount,
order.makerAssetAmount.safeSub(order.takerFee),
order.takerAssetAmount
);
// Approve the proxy to spend the maker token.
// It isn't worth computing the actual taker fee
// since `approveIfBelow()` will set the allowance to infinite. We
// just need a reasonable upper bound to avoid unnecessarily re-approving.
takerFeeToken.approveIfBelow(erc20Proxy, order.takerFee);
} else if (takerFeeToken != takerToken) {
// Only support taker or maker asset denominated taker fees.
LibTransformERC20RichErrors.InvalidTakerFeeTokenError(
address(takerFeeToken)
).rrevert();
}
// Emit an event if we do not have sufficient ETH to cover the protocol fee.
if (state.ethRemaining < state.protocolFee) {
bytes32 orderHash = zeroEx.getLimitOrderHash(orderInfo.order);
emit ProtocolFeeUnfunded(orderHash);
return results; // Empty results.
}
// Perform the fill.
return _fillOrder(
order,
signature,
takerTokenFillAmount,
state,
takerFeeToken == takerToken
);
}
/// @dev Attempt to fill an order. If the fill reverts, the revert will be
/// swallowed and `results` will be zeroed out.
/// @param order The order to fill.
/// @param signature The order signature.
/// @param takerAssetFillAmount How much taker asset to fill.
/// @param state Intermediate state variables to get around stack limits.
/// @param isTakerFeeInTakerToken Whether the taker fee token is the same as the
/// taker token.
function _fillOrder(
IExchange.Order memory order,
bytes memory signature,
uint256 takerAssetFillAmount,
FillState memory state,
bool isTakerFeeInTakerToken
)
private
returns (FillOrderResults memory results)
{
// Clamp to remaining taker asset amount or order size.
uint256 availableTakerAssetFillAmount =
takerAssetFillAmount.min256(order.takerAssetAmount);
availableTakerAssetFillAmount =
availableTakerAssetFillAmount.min256(state.takerTokenBalanceRemaining);
// If it is a Bridge order we fill this directly through the BridgeAdapter
if (order.makerAssetData.readBytes4(0) == ERC20_BRIDGE_PROXY_ID) {
(bool success, bytes memory resultData) = address(bridgeAdapter).delegatecall(
abi.encodeWithSelector(
IBridgeAdapter.trade.selector,
order.makerAssetData,
address(_getTokenFromERC20AssetData(order.takerAssetData)),
availableTakerAssetFillAmount
try
zeroEx.fillLimitOrder
{value: state.protocolFee}
(
orderInfo.order,
orderInfo.signature,
takerTokenFillAmount.safeDowncastToUint128()
)
);
if (success) {
results.makerTokenBoughtAmount = abi.decode(resultData, (uint256));
results.takerTokenSoldAmount = availableTakerAssetFillAmount;
// protocol fee paid remains 0
}
return results;
} else {
// If the order taker address is set to this contract's address then
// this is an RFQT order, and we will only fill it if allowed to.
if (order.takerAddress == address(this) && !state.isRfqtAllowed) {
return results; // Empty results.
}
// Emit an event if we do not have sufficient ETH to cover the protocol fee.
if (state.ethRemaining < state.protocolFee) {
bytes32 orderHash = LibOrderHash.getTypedDataHash(
order,
exchange.EIP712_EXCHANGE_DOMAIN_HASH()
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
if (orderInfo.order.takerTokenFeeAmount > 0) {
takerTokenFilledAmount = takerTokenFilledAmount.safeAdd128(
LibMathV06.getPartialAmountFloor(
takerTokenFilledAmount,
orderInfo.order.takerAmount,
orderInfo.order.takerTokenFeeAmount
).safeDowncastToUint128()
);
emit ProtocolFeeUnfunded(orderHash);
return results;
}
try
exchange.fillOrder
{value: state.protocolFee}
(order, availableTakerAssetFillAmount, signature)
returns (IExchange.FillResults memory fillResults)
{
results.makerTokenBoughtAmount = fillResults.makerAssetFilledAmount;
results.takerTokenSoldAmount = fillResults.takerAssetFilledAmount;
results.protocolFeePaid = fillResults.protocolFeePaid;
// If the taker fee is payable in the taker asset, include the
// taker fee in the total amount sold.
if (isTakerFeeInTakerToken) {
results.takerTokenSoldAmount =
results.takerTokenSoldAmount.safeAdd(fillResults.takerFeePaid);
}
} catch (bytes memory) {
// Swallow failures, leaving all results as zero.
}
}
results.takerTokenSoldAmount = takerTokenFilledAmount;
results.makerTokenBoughtAmount = makerTokenFilledAmount;
results.protocolFeePaid = state.protocolFee;
} catch {}
}
/// @dev Extract the token from plain ERC20 asset data.
/// If the asset-data is empty, a zero token address will be returned.
/// @param assetData The order asset data.
function _getTokenFromERC20AssetData(bytes memory assetData)
// Fill a single RFQ order.
function _fillRfqOrder(
RfqOrderInfo memory orderInfo,
TransformData memory data,
FillState memory state
)
private
returns (FillOrderResults memory results)
{
uint256 takerTokenFillAmount = LibSafeMathV06.min256(
_computeTakerTokenFillAmount(
data,
state,
orderInfo.order.takerAmount,
orderInfo.order.makerAmount,
0
),
orderInfo.maxTakerTokenFillAmount
);
try
zeroEx.fillRfqOrder
(
orderInfo.order,
orderInfo.signature,
takerTokenFillAmount.safeDowncastToUint128()
)
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
results.takerTokenSoldAmount = takerTokenFilledAmount;
results.makerTokenBoughtAmount = makerTokenFilledAmount;
} catch {}
}
// Compute the next taker token fill amount of a generic order.
function _computeTakerTokenFillAmount(
TransformData memory data,
FillState memory state,
uint256 orderTakerAmount,
uint256 orderMakerAmount,
uint256 orderTakerTokenFeeAmount
)
private
pure
returns (IERC20TokenV06 token)
returns (uint256 takerTokenFillAmount)
{
if (assetData.length == 0) {
return IERC20TokenV06(address(0));
if (data.side == Side.Sell) {
takerTokenFillAmount = data.fillAmount.safeSub(state.soldAmount);
if (orderTakerTokenFeeAmount != 0) {
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
takerTokenFillAmount,
orderTakerAmount.safeAdd(orderTakerTokenFeeAmount),
orderTakerAmount
);
}
} else { // Buy
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
data.fillAmount.safeSub(state.boughtAmount),
orderMakerAmount,
orderTakerAmount
);
}
if (assetData.length != 36 ||
LibBytesV06.readBytes4(assetData, 0) != ERC20_ASSET_PROXY_ID)
{
LibTransformERC20RichErrors
.InvalidERC20AssetDataError(assetData)
.rrevert();
return LibSafeMathV06.min256(
LibSafeMathV06.min256(takerTokenFillAmount, orderTakerAmount),
state.takerTokenBalanceRemaining
);
}
// Convert possible proportional values to absolute quantities.
function _normalizeFillAmount(uint256 rawAmount, uint256 balance)
private
pure
returns (uint256 normalized)
{
if ((rawAmount & HIGH_BIT) == HIGH_BIT) {
// If the high bit of `rawAmount` is set then the lower 255 bits
// specify a fraction of `balance`.
return LibSafeMathV06.min256(
balance
* LibSafeMathV06.min256(rawAmount & LOWER_255_BITS, 1e18)
/ 1e18,
balance
);
}
return IERC20TokenV06(LibBytesV06.readAddress(assetData, 16));
return rawAmount;
}
}

View File

@@ -20,7 +20,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "./mixins/MixinAdapterAddresses.sol";
import "./IBridgeAdapter.sol";
import "./BridgeSource.sol";
import "./mixins/MixinBalancer.sol";
import "./mixins/MixinBancor.sol";
import "./mixins/MixinCoFiX.sol";
@@ -38,7 +39,7 @@ import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinZeroExBridge.sol";
contract BridgeAdapter is
MixinAdapterAddresses,
IBridgeAdapter,
MixinBalancer,
MixinBancor,
MixinCoFiX,
@@ -55,203 +56,146 @@ contract BridgeAdapter is
MixinUniswapV2,
MixinZeroExBridge
{
/// @dev Emitted when a trade occurs.
/// @param inputToken The token the bridge is converting from.
/// @param outputToken The token the bridge is converting to.
/// @param inputTokenAmount Amount of input token.
/// @param outputTokenAmount Amount of output token.
/// @param from The bridge address, indicating the underlying source of the fill.
/// @param to The `to` address, currrently `address(this)`
event ERC20BridgeTransfer(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
address from,
address to
);
address private immutable BALANCER_BRIDGE_ADDRESS;
address private immutable BANCOR_BRIDGE_ADDRESS;
address private immutable COFIX_BRIDGE_ADDRESS;
address private immutable CREAM_BRIDGE_ADDRESS;
address private immutable CURVE_BRIDGE_ADDRESS;
address private immutable CRYPTO_COM_BRIDGE_ADDRESS;
address private immutable DODO_BRIDGE_ADDRESS;
address private immutable KYBER_BRIDGE_ADDRESS;
address private immutable MOONISWAP_BRIDGE_ADDRESS;
address private immutable MSTABLE_BRIDGE_ADDRESS;
address private immutable OASIS_BRIDGE_ADDRESS;
address private immutable SHELL_BRIDGE_ADDRESS;
address private immutable SNOW_SWAP_BRIDGE_ADDRESS;
address private immutable SUSHISWAP_BRIDGE_ADDRESS;
address private immutable SWERVE_BRIDGE_ADDRESS;
address private immutable UNISWAP_BRIDGE_ADDRESS;
address private immutable UNISWAP_V2_BRIDGE_ADDRESS;
constructor(AdapterAddresses memory addresses)
constructor(IEtherTokenV06 weth)
public
MixinBalancer()
MixinBancor(addresses)
MixinBancor(weth)
MixinCoFiX()
MixinCurve()
MixinCryptoCom()
MixinDodo(addresses)
MixinKyber(addresses)
MixinMooniswap(addresses)
MixinMStable(addresses)
MixinOasis(addresses)
MixinDodo()
MixinKyber(weth)
MixinMooniswap(weth)
MixinMStable()
MixinOasis()
MixinShell()
MixinSushiswap(addresses)
MixinUniswap(addresses)
MixinUniswapV2(addresses)
MixinSushiswap()
MixinUniswap(weth)
MixinUniswapV2()
MixinZeroExBridge()
{
BALANCER_BRIDGE_ADDRESS = addresses.balancerBridge;
BANCOR_BRIDGE_ADDRESS = addresses.bancorBridge;
COFIX_BRIDGE_ADDRESS = addresses.cofixBridge;
CURVE_BRIDGE_ADDRESS = addresses.curveBridge;
CRYPTO_COM_BRIDGE_ADDRESS = addresses.cryptoComBridge;
KYBER_BRIDGE_ADDRESS = addresses.kyberBridge;
MOONISWAP_BRIDGE_ADDRESS = addresses.mooniswapBridge;
MSTABLE_BRIDGE_ADDRESS = addresses.mStableBridge;
OASIS_BRIDGE_ADDRESS = addresses.oasisBridge;
SHELL_BRIDGE_ADDRESS = addresses.shellBridge;
SUSHISWAP_BRIDGE_ADDRESS = addresses.sushiswapBridge;
SWERVE_BRIDGE_ADDRESS = addresses.swerveBridge;
UNISWAP_BRIDGE_ADDRESS = addresses.uniswapBridge;
UNISWAP_V2_BRIDGE_ADDRESS = addresses.uniswapV2Bridge;
CREAM_BRIDGE_ADDRESS = addresses.creamBridge;
SNOW_SWAP_BRIDGE_ADDRESS = addresses.snowSwapBridge;
DODO_BRIDGE_ADDRESS = addresses.dodoBridge;
}
{}
function trade(
bytes calldata makerAssetData,
BridgeOrder memory order,
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount
)
external
public
override
returns (uint256 boughtAmount)
{
(
IERC20TokenV06 buyToken,
address bridgeAddress,
bytes memory bridgeData
) = abi.decode(
makerAssetData[4:],
(IERC20TokenV06, address, bytes)
);
require(
bridgeAddress != address(this) && bridgeAddress != address(0),
"BridgeAdapter/INVALID_BRIDGE_ADDRESS"
);
if (bridgeAddress == CURVE_BRIDGE_ADDRESS ||
bridgeAddress == SWERVE_BRIDGE_ADDRESS ||
bridgeAddress == SNOW_SWAP_BRIDGE_ADDRESS) {
if (order.source == BridgeSource.CURVE ||
order.source == BridgeSource.SWERVE ||
order.source == BridgeSource.SNOWSWAP) {
boughtAmount = _tradeCurve(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == SUSHISWAP_BRIDGE_ADDRESS) {
boughtAmount = _tradeSushiswap(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == UNISWAP_V2_BRIDGE_ADDRESS) {
boughtAmount = _tradeUniswapV2(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == UNISWAP_BRIDGE_ADDRESS) {
boughtAmount = _tradeUniswap(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS ||
bridgeAddress == CREAM_BRIDGE_ADDRESS) {
boughtAmount = _tradeBalancer(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == KYBER_BRIDGE_ADDRESS) {
boughtAmount = _tradeKyber(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == MOONISWAP_BRIDGE_ADDRESS) {
boughtAmount = _tradeMooniswap(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == MSTABLE_BRIDGE_ADDRESS) {
boughtAmount = _tradeMStable(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == OASIS_BRIDGE_ADDRESS) {
boughtAmount = _tradeOasis(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == SHELL_BRIDGE_ADDRESS) {
boughtAmount = _tradeShell(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == DODO_BRIDGE_ADDRESS) {
boughtAmount = _tradeDodo(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == CRYPTO_COM_BRIDGE_ADDRESS) {
boughtAmount = _tradeCryptoCom(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == BANCOR_BRIDGE_ADDRESS) {
boughtAmount = _tradeBancor(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == COFIX_BRIDGE_ADDRESS) {
boughtAmount = _tradeCoFiX(
buyToken,
sellAmount,
bridgeData
);
} else {
boughtAmount = _tradeZeroExBridge(
bridgeAddress,
sellToken,
buyToken,
sellAmount,
bridgeData
order.bridgeData
);
} else if (order.source == BridgeSource.SUSHISWAP) {
boughtAmount = _tradeSushiswap(
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.UNISWAPV2) {
boughtAmount = _tradeUniswapV2(
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.UNISWAP) {
boughtAmount = _tradeUniswap(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.BALANCER ||
order.source == BridgeSource.CREAM) {
boughtAmount = _tradeBalancer(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.KYBER) {
boughtAmount = _tradeKyber(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.MOONISWAP) {
boughtAmount = _tradeMooniswap(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.MSTABLE) {
boughtAmount = _tradeMStable(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.OASIS) {
boughtAmount = _tradeOasis(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.SHELL) {
boughtAmount = _tradeShell(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.DODO) {
boughtAmount = _tradeDodo(
sellToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.CRYPTOCOM) {
boughtAmount = _tradeCryptoCom(
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.BANCOR) {
boughtAmount = _tradeBancor(
buyToken,
sellAmount,
order.bridgeData
);
} else if (order.source == BridgeSource.COFIX) {
boughtAmount = _tradeCoFiX(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else {
boughtAmount = _tradeZeroExBridge(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
}
emit ERC20BridgeTransfer(
emit BridgeFill(
order.source,
sellToken,
buyToken,
sellAmount,
boughtAmount,
bridgeAddress,
address(this)
boughtAmount
);
}
}

View File

@@ -0,0 +1,45 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
library BridgeSource {
uint256 constant internal BALANCER = 0;
uint256 constant internal BANCOR = 1;
uint256 constant internal COFIX = 2;
uint256 constant internal CURVE = 3;
uint256 constant internal CREAM = 4;
uint256 constant internal CRYPTOCOM = 5;
uint256 constant internal DODO = 6;
uint256 constant internal KYBER = 7;
uint256 constant internal LIQUIDITYPROVIDER = 8;
uint256 constant internal MOONISWAP = 9;
uint256 constant internal MSTABLE = 10;
uint256 constant internal OASIS = 11;
uint256 constant internal SHELL = 12;
uint256 constant internal SNOWSWAP = 13;
uint256 constant internal SUSHISWAP = 14;
uint256 constant internal SWERVE = 15;
uint256 constant internal UNISWAP = 16;
uint256 constant internal UNISWAPV2 = 17;
// New sources should be APPENDED to this list, taking the next highest
// integer value.
}

View File

@@ -18,12 +18,38 @@
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
interface IBridgeAdapter {
struct BridgeOrder {
uint256 source;
uint256 takerTokenAmount;
uint256 makerTokenAmount;
bytes bridgeData;
}
/// @dev Emitted when tokens are swapped with an external source.
/// @param source The unique ID for the source. See `BridgeSource.sol`
/// @param inputToken The token the bridge is converting from.
/// @param outputToken The token the bridge is converting to.
/// @param inputTokenAmount Amount of input token sold.
/// @param outputTokenAmount Amount of output token bought.
event BridgeFill(
uint256 source,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount
);
function trade(
bytes calldata makerAssetData,
address fromTokenAddress,
BridgeOrder calldata order,
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount
)
external

View File

@@ -1,55 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
contract MixinAdapterAddresses
{
struct AdapterAddresses {
// Bridges
address balancerBridge;
address bancorBridge;
address cofixBridge;
address creamBridge;
address curveBridge;
address cryptoComBridge;
address dodoBridge;
address kyberBridge;
address mooniswapBridge;
address mStableBridge;
address oasisBridge;
address shellBridge;
address snowSwapBridge;
address swerveBridge;
address sushiswapBridge;
address uniswapBridge;
address uniswapV2Bridge;
// Exchanges
address kyberNetworkProxy;
address oasis;
address sushiswapRouter;
address uniswapV2Router;
address uniswapExchangeFactory;
address mStable;
address dodoHelper;
// Other
address weth;
}
}

View File

@@ -46,6 +46,7 @@ contract MixinBalancer {
using LibERC20TokenV06 for IERC20TokenV06;
function _tradeBalancer(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -54,9 +55,9 @@ contract MixinBalancer {
returns (uint256 boughtAmount)
{
// Decode the bridge data.
(IERC20TokenV06 sellToken, IBalancerPool pool) = abi.decode(
(IBalancerPool pool) = abi.decode(
bridgeData,
(IERC20TokenV06, IBalancerPool)
(IBalancerPool)
);
sellToken.approveIfBelow(
address(pool),

View File

@@ -24,12 +24,12 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "../IBridgeAdapter.sol";
interface IBancorNetwork {
function convertByPath(
address[] calldata _path,
IERC20TokenV06[] calldata _path,
uint256 _amount,
uint256 _minReturn,
address _beneficiary,
@@ -42,17 +42,17 @@ interface IBancorNetwork {
}
contract MixinBancor is
MixinAdapterAddresses
{
contract MixinBancor {
/// @dev Bancor ETH pseudo-address.
address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
IERC20TokenV06 constant public BANCOR_ETH_ADDRESS =
IERC20TokenV06(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
IEtherTokenV06 private immutable WETH;
constructor(AdapterAddresses memory addresses)
constructor(IEtherTokenV06 weth)
public
{
WETH = IEtherTokenV06(addresses.weth);
WETH = weth;
}
function _tradeBancor(
@@ -64,17 +64,22 @@ contract MixinBancor is
returns (uint256 boughtAmount)
{
// Decode the bridge data.
(
address[] memory path,
address bancorNetworkAddress
// solhint-disable indent
) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
IBancorNetwork bancorNetworkAddress;
IERC20TokenV06[] memory path;
{
address[] memory _path;
(
bancorNetworkAddress,
_path
) = abi.decode(bridgeData, (IBancorNetwork, address[]));
// To get around `abi.decode()` not supporting interface array types.
assembly { path := _path }
}
require(path.length >= 2, "MixinBancor/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
path[path.length - 1] == address(buyToken) ||
(path[path.length - 1] == BANCOR_ETH_ADDRESS && address(buyToken) == address(WETH)),
path[path.length - 1] == buyToken ||
(path[path.length - 1] == BANCOR_ETH_ADDRESS && buyToken == WETH),
"MixinBancor/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
@@ -88,14 +93,14 @@ contract MixinBancor is
} else {
// Grant an allowance to the Bancor Network.
LibERC20TokenV06.approveIfBelow(
IERC20TokenV06(path[0]),
bancorNetworkAddress,
path[0],
address(bancorNetworkAddress),
sellAmount
);
}
// Convert the tokens
boughtAmount = IBancorNetwork(bancorNetworkAddress).convertByPath{value: payableAmount}(
boughtAmount = bancorNetworkAddress.convertByPath{value: payableAmount}(
path, // path originating with source token and terminating in destination token
sellAmount, // amount of source token to trade
1, // minimum amount of destination token expected to receive

View File

@@ -23,7 +23,6 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface ICoFiXRouter {
@@ -53,15 +52,20 @@ interface ICoFiXPair {
function swapWithExact(address outToken, address to)
external
payable
returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[4] memory tradeInfo);
returns (
uint amountIn,
uint amountOut,
uint oracleFeeChange,
uint256[4] memory tradeInfo
);
}
contract MixinCoFiX is
MixinAdapterAddresses
{
contract MixinCoFiX {
using LibERC20TokenV06 for IERC20TokenV06;
function _tradeCoFiX(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -69,15 +73,16 @@ contract MixinCoFiX is
internal
returns (uint256 boughtAmount)
{
(address fromTokenAddress, uint256 fee, address pool) = abi.decode(bridgeData, (address, uint256, address));
(uint256 fee, ICoFiXPair pool) = abi.decode(bridgeData, (uint256, ICoFiXPair));
// Transfer tokens into the pool
LibERC20TokenV06.compatTransfer(
IERC20TokenV06(fromTokenAddress),
pool,
sellAmount);
sellToken,
address(pool),
sellAmount
);
// Call the swap exact with the tokens now in the pool
// pay the NEST Oracle fee with ETH
(/* In */, boughtAmount, , ) = ICoFiXPair(pool).swapWithExact{value: fee}(
(/* In */, boughtAmount, , ) = pool.swapWithExact{value: fee}(
address(buyToken),
address(this)
);

View File

@@ -37,21 +37,24 @@ contract MixinCryptoCom
internal
returns (uint256 boughtAmount)
{
// solhint-disable indent
address[] memory path;
address router;
(path, router) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
IUniswapV2Router02 router;
IERC20TokenV06[] memory path;
{
address[] memory _path;
(router, _path) = abi.decode(bridgeData, (IUniswapV2Router02, address[]));
// To get around `abi.decode()` not supporting interface array types.
assembly { path := _path }
}
require(path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(path.length >= 2, "MixinCryptoCom/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
path[path.length - 1] == address(buyToken),
"CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
path[path.length - 1] == buyToken,
"MixinCryptoCom/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
// Grant the CryptoCom router an allowance to sell the first token.
IERC20TokenV06(path[0]).approveIfBelow(router, sellAmount);
path[0].approveIfBelow(address(router), sellAmount);
uint[] memory amounts = IUniswapV2Router02(router).swapExactTokensForTokens(
uint[] memory amounts = router.swapExactTokensForTokens(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.

View File

@@ -35,12 +35,12 @@ contract MixinCurve {
struct CurveBridgeData {
address curveAddress;
bytes4 exchangeFunctionSelector;
IERC20TokenV06 sellToken;
int128 fromCoinIdx;
int128 toCoinIdx;
}
function _tradeCurve(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -50,7 +50,7 @@ contract MixinCurve {
{
// Decode the bridge data to get the Curve metadata.
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
data.sellToken.approveIfBelow(data.curveAddress, sellAmount);
sellToken.approveIfBelow(data.curveAddress, sellAmount);
uint256 beforeBalance = buyToken.balanceOf(address(this));
(bool success, bytes memory resultData) =
data.curveAddress.call(abi.encodeWithSelector(

View File

@@ -23,55 +23,60 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface IDODOHelper {
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
}
import "../IBridgeAdapter.sol";
interface IDODO {
function sellBaseToken(
uint256 amount,
uint256 minReceiveQuote,
bytes calldata data
)
external
returns (uint256);
function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
function buyBaseToken(
uint256 amount,
uint256 maxPayQuote,
bytes calldata data
)
external
returns (uint256);
}
contract MixinDodo is
MixinAdapterAddresses
{
interface IDODOHelper {
function querySellQuoteToken(
IDODO dodo,
uint256 amount
)
external
view
returns (uint256);
}
contract MixinDodo {
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the `DOODO Helper` contract.
IDODOHelper private immutable DODO_HELPER;
constructor(AdapterAddresses memory addresses)
public
{
DODO_HELPER = IDODOHelper(addresses.dodoHelper);
}
function _tradeDodo(
IERC20TokenV06 /* buyToken */,
IERC20TokenV06 sellToken,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
(address fromTokenAddress,
address pool,
bool isSellBase) = abi.decode(bridgeData, (address, address, bool));
(IDODOHelper helper, IDODO pool, bool isSellBase) =
abi.decode(bridgeData, (IDODOHelper, IDODO, bool));
// Grant the Dodo pool contract an allowance to sell the first token.
IERC20TokenV06(fromTokenAddress).approveIfBelow(pool, sellAmount);
sellToken.approveIfBelow(address(pool), sellAmount);
if (isSellBase) {
// Sell the Base token directly against the contract
boughtAmount = IDODO(pool).sellBaseToken(
boughtAmount = pool.sellBaseToken(
// amount to sell
sellAmount,
// min receive amount
@@ -80,11 +85,11 @@ contract MixinDodo is
);
} else {
// Need to re-calculate the sell quote amount into buyBase
boughtAmount = DODO_HELPER.querySellQuoteToken(
boughtAmount = helper.querySellQuoteToken(
pool,
sellAmount
);
IDODO(pool).buyBaseToken(
pool.buyBaseToken(
// amount to buy
boughtAmount,
// max pay amount

View File

@@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "../IBridgeAdapter.sol";
interface IKyberNetworkProxy {
@@ -54,26 +54,24 @@ interface IKyberNetworkProxy {
returns (uint256 boughtAmount);
}
contract MixinKyber is
MixinAdapterAddresses
{
contract MixinKyber {
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Address indicating the trade is using ETH
address private immutable KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
IERC20TokenV06 private immutable KYBER_ETH_ADDRESS =
IERC20TokenV06(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
/// @dev Mainnet address of the WETH contract.
IEtherTokenV06 private immutable WETH;
/// @dev Mainnet address of the KyberNetworkProxy contract.
IKyberNetworkProxy private immutable KYBER_NETWORK_PROXY;
constructor(AdapterAddresses memory addresses)
constructor(IEtherTokenV06 weth)
public
{
WETH = IEtherTokenV06(addresses.weth);
KYBER_NETWORK_PROXY = IKyberNetworkProxy(addresses.kyberNetworkProxy);
WETH = weth;
}
function _tradeKyber(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -81,15 +79,15 @@ contract MixinKyber is
internal
returns (uint256 boughtAmount)
{
(IERC20TokenV06 sellToken, bytes memory hint) =
abi.decode(bridgeData, (IERC20TokenV06, bytes));
(IKyberNetworkProxy kyber, bytes memory hint) =
abi.decode(bridgeData, (IKyberNetworkProxy, bytes));
uint256 payableAmount = 0;
if (sellToken != WETH) {
// If the input token is not WETH, grant an allowance to the exchange
// to spend them.
sellToken.approveIfBelow(
address(KYBER_NETWORK_PROXY),
address(kyber),
sellAmount
);
} else {
@@ -100,13 +98,13 @@ contract MixinKyber is
// Try to sell all of this contract's input token balance through
// `KyberNetworkProxy.trade()`.
boughtAmount = KYBER_NETWORK_PROXY.tradeWithHint{ value: payableAmount }(
boughtAmount = kyber.tradeWithHint{ value: payableAmount }(
// Input token.
sellToken == WETH ? IERC20TokenV06(KYBER_ETH_ADDRESS) : sellToken,
sellToken == WETH ? KYBER_ETH_ADDRESS : sellToken,
// Sell amount.
sellAmount,
// Output token.
buyToken == WETH ? IERC20TokenV06(KYBER_ETH_ADDRESS) : buyToken,
buyToken == WETH ? KYBER_ETH_ADDRESS : buyToken,
// Transfer to this contract
address(uint160(address(this))),
// Buy as much as possible.

View File

@@ -22,7 +22,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "../IBridgeAdapter.sol";
interface IMStable {
@@ -37,21 +37,12 @@ interface IMStable {
returns (uint256 boughtAmount);
}
contract MixinMStable is
MixinAdapterAddresses
{
contract MixinMStable {
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the mStable mUSD contract.
IMStable private immutable MSTABLE;
constructor(AdapterAddresses memory addresses)
public
{
MSTABLE = IMStable(addresses.mStable);
}
function _tradeMStable(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -59,12 +50,12 @@ contract MixinMStable is
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the `sellToken`.
(IERC20TokenV06 sellToken) = abi.decode(bridgeData, (IERC20TokenV06));
// Grant an allowance to the exchange to spend `sellToken` token.
sellToken.approveIfBelow(address(MSTABLE), sellAmount);
(IMStable mstable) = abi.decode(bridgeData, (IMStable));
boughtAmount = MSTABLE.swap(
// Grant an allowance to the exchange to spend `sellToken` token.
sellToken.approveIfBelow(address(mstable), sellAmount);
boughtAmount = mstable.swap(
sellToken,
buyToken,
sellAmount,

View File

@@ -24,7 +24,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "../IBridgeAdapter.sol";
/// @dev Moooniswap pool interface.
@@ -43,22 +43,22 @@ interface IMooniswapPool {
}
/// @dev BridgeAdapter mixin for mooniswap.
contract MixinMooniswap is
MixinAdapterAddresses
{
contract MixinMooniswap {
using LibERC20TokenV06 for IERC20TokenV06;
using LibERC20TokenV06 for IEtherTokenV06;
/// @dev WETH token.
IEtherTokenV06 private immutable WETH;
constructor(AdapterAddresses memory addresses)
constructor(IEtherTokenV06 weth)
public
{
WETH = IEtherTokenV06(addresses.weth);
WETH = weth;
}
function _tradeMooniswap(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -66,8 +66,7 @@ contract MixinMooniswap is
internal
returns (uint256 boughtAmount)
{
(IERC20TokenV06 sellToken, IMooniswapPool pool) =
abi.decode(bridgeData, (IERC20TokenV06, IMooniswapPool));
(IMooniswapPool pool) = abi.decode(bridgeData, (IMooniswapPool));
// Convert WETH to ETH.
uint256 ethValue = 0;

View File

@@ -22,7 +22,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "../IBridgeAdapter.sol";
interface IOasis {
@@ -42,21 +42,12 @@ interface IOasis {
returns (uint256 boughtAmount);
}
contract MixinOasis is
MixinAdapterAddresses
{
contract MixinOasis {
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the Oasis `MatchingMarket` contract.
IOasis private immutable OASIS;
constructor(AdapterAddresses memory addresses)
public
{
OASIS = IOasis(addresses.oasis);
}
function _tradeOasis(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -64,15 +55,16 @@ contract MixinOasis is
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the `sellToken`.
(IERC20TokenV06 sellToken) = abi.decode(bridgeData, (IERC20TokenV06));
(IOasis oasis) = abi.decode(bridgeData, (IOasis));
// Grant an allowance to the exchange to spend `sellToken` token.
sellToken.approveIfBelow(
address(OASIS),
address(oasis),
sellAmount
);
// Try to sell all of this contract's `sellToken` token balance.
boughtAmount = OASIS.sellAllAmount(
boughtAmount = oasis.sellAllAmount(
sellToken,
sellAmount,
buyToken,

View File

@@ -23,13 +23,12 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface IShell {
function originSwap(
address from,
address to,
IERC20TokenV06 from,
IERC20TokenV06 to,
uint256 fromAmount,
uint256 minTargetAmount,
uint256 deadline
@@ -38,12 +37,12 @@ interface IShell {
returns (uint256 toAmount);
}
contract MixinShell is
MixinAdapterAddresses
{
contract MixinShell {
using LibERC20TokenV06 for IERC20TokenV06;
function _tradeShell(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -51,17 +50,17 @@ contract MixinShell is
internal
returns (uint256 boughtAmount)
{
(address fromTokenAddress, address pool) = abi.decode(bridgeData, (address, address));
IShell pool = abi.decode(bridgeData, (IShell));
// Grant the Shell contract an allowance to sell the first token.
IERC20TokenV06(fromTokenAddress).approveIfBelow(
pool,
IERC20TokenV06(sellToken).approveIfBelow(
address(pool),
sellAmount
);
boughtAmount = IShell(pool).originSwap(
fromTokenAddress,
address(buyToken),
boughtAmount = pool.originSwap(
sellToken,
buyToken,
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.

View File

@@ -23,23 +23,12 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "./MixinUniswapV2.sol";
contract MixinSushiswap is
MixinAdapterAddresses
{
contract MixinSushiswap {
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the `SushiswapRouter` contract.
IUniswapV2Router02 private immutable SUSHISWAP_ROUTER;
constructor(AdapterAddresses memory addresses)
public
{
SUSHISWAP_ROUTER = IUniswapV2Router02(addresses.sushiswapRouter);
}
function _tradeSushiswap(
IERC20TokenV06 buyToken,
uint256 sellAmount,
@@ -48,22 +37,28 @@ contract MixinSushiswap is
internal
returns (uint256 boughtAmount)
{
// solhint-disable indent
address[] memory path = abi.decode(bridgeData, (address[]));
// solhint-enable indent
IERC20TokenV06[] memory path;
IUniswapV2Router02 router;
{
address[] memory _path;
(router, _path) =
abi.decode(bridgeData, (IUniswapV2Router02, address[]));
// To get around `abi.decode()` not supporting interface array types.
assembly { path := _path }
}
require(path.length >= 2, "SushiswapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(path.length >= 2, "MixinSushiswap/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
path[path.length - 1] == address(buyToken),
"SushiswapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
path[path.length - 1] == buyToken,
"MixinSushiswap/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
// Grant the Uniswap router an allowance to sell the first token.
IERC20TokenV06(path[0]).approveIfBelow(
address(SUSHISWAP_ROUTER),
path[0].approveIfBelow(
address(router),
sellAmount
);
uint[] memory amounts = SUSHISWAP_ROUTER.swapExactTokensForTokens(
uint[] memory amounts = router.swapExactTokensForTokens(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.

View File

@@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "../IBridgeAdapter.sol";
interface IUniswapExchangeFactory {
@@ -103,24 +103,21 @@ interface IUniswapExchange {
returns (uint256 tokensBought);
}
contract MixinUniswap is
MixinAdapterAddresses
{
contract MixinUniswap {
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the WETH contract.
IEtherTokenV06 private immutable WETH;
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
IUniswapExchangeFactory private immutable UNISWAP_EXCHANGE_FACTORY;
constructor(AdapterAddresses memory addresses)
constructor(IEtherTokenV06 weth)
public
{
WETH = IEtherTokenV06(addresses.weth);
UNISWAP_EXCHANGE_FACTORY = IUniswapExchangeFactory(addresses.uniswapExchangeFactory);
WETH = weth;
}
function _tradeUniswap(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
@@ -128,11 +125,12 @@ contract MixinUniswap is
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the `sellToken`.
(IERC20TokenV06 sellToken) = abi.decode(bridgeData, (IERC20TokenV06));
IUniswapExchangeFactory exchangeFactory =
abi.decode(bridgeData, (IUniswapExchangeFactory));
// Get the exchange for the token pair.
IUniswapExchange exchange = _getUniswapExchangeForTokenPair(
exchangeFactory,
sellToken,
buyToken
);
@@ -197,10 +195,12 @@ contract MixinUniswap is
/// @dev Retrieves the uniswap exchange for a given token pair.
/// In the case of a WETH-token exchange, this will be the non-WETH token.
/// In th ecase of a token-token exchange, this will be the first token.
/// @param exchangeFactory The exchange factory.
/// @param sellToken The address of the token we are converting from.
/// @param buyToken The address of the token we are converting to.
/// @return exchange The uniswap exchange.
function _getUniswapExchangeForTokenPair(
IUniswapExchangeFactory exchangeFactory,
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken
)
@@ -210,8 +210,8 @@ contract MixinUniswap is
{
// Whichever isn't WETH is the exchange token.
exchange = sellToken == WETH
? UNISWAP_EXCHANGE_FACTORY.getExchange(buyToken)
: UNISWAP_EXCHANGE_FACTORY.getExchange(sellToken);
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
? exchangeFactory.getExchange(buyToken)
: exchangeFactory.getExchange(sellToken);
require(address(exchange) != address(0), "MixinUniswap/NO_EXCHANGE");
}
}

View File

@@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "../IBridgeAdapter.sol";
/*
UniswapV2
@@ -42,26 +42,16 @@ interface IUniswapV2Router02 {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
IERC20TokenV06[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
contract MixinUniswapV2 is
MixinAdapterAddresses
{
contract MixinUniswapV2 {
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the `UniswapV2Router02` contract.
IUniswapV2Router02 private immutable UNISWAP_V2_ROUTER;
constructor(AdapterAddresses memory addresses)
public
{
UNISWAP_V2_ROUTER = IUniswapV2Router02(addresses.uniswapV2Router);
}
function _tradeUniswapV2(
IERC20TokenV06 buyToken,
uint256 sellAmount,
@@ -70,22 +60,24 @@ contract MixinUniswapV2 is
internal
returns (uint256 boughtAmount)
{
// solhint-disable indent
address[] memory path = abi.decode(bridgeData, (address[]));
// solhint-enable indent
IUniswapV2Router02 router;
IERC20TokenV06[] memory path;
{
address[] memory _path;
(router, _path) = abi.decode(bridgeData, (IUniswapV2Router02, address[]));
// To get around `abi.decode()` not supporting interface array types.
assembly { path := _path }
}
require(path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(path.length >= 2, "MixinUniswapV3/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
path[path.length - 1] == address(buyToken),
"UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
path[path.length - 1] == buyToken,
"MixinUniswapV2/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
// Grant the Uniswap router an allowance to sell the first token.
IERC20TokenV06(path[0]).approveIfBelow(
address(UNISWAP_V2_ROUTER),
sellAmount
);
path[0].approveIfBelow(address(router), sellAmount);
uint[] memory amounts = UNISWAP_V2_ROUTER.swapExactTokensForTokens(
uint[] memory amounts = router.swapExactTokensForTokens(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.

View File

@@ -31,7 +31,6 @@ contract MixinZeroExBridge {
using LibSafeMathV06 for uint256;
function _tradeZeroExBridge(
address bridgeAddress,
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
@@ -40,17 +39,19 @@ contract MixinZeroExBridge {
internal
returns (uint256 boughtAmount)
{
(ILiquidityProvider provider, bytes memory lpData) =
abi.decode(bridgeData, (ILiquidityProvider, bytes));
// Trade the good old fashioned way
sellToken.compatTransfer(
bridgeAddress,
address(provider),
sellAmount
);
boughtAmount = ILiquidityProvider(bridgeAddress).sellTokenForToken(
boughtAmount = provider.sellTokenForToken(
address(sellToken),
address(buyToken),
address(this), // recipient
1, // minBuyAmount
bridgeData
lpData
);
}
}

View File

@@ -1,113 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
/// @dev Interface to the V3 Exchange.
interface IExchange {
/// @dev V3 Order structure.
struct Order {
// Address that created the order.
address makerAddress;
// Address that is allowed to fill the order.
// If set to 0, any address is allowed to fill the order.
address takerAddress;
// Address that will recieve fees when order is filled.
address feeRecipientAddress;
// Address that is allowed to call Exchange contract methods that affect this order.
// If set to 0, any address is allowed to call these methods.
address senderAddress;
// Amount of makerAsset being offered by maker. Must be greater than 0.
uint256 makerAssetAmount;
// Amount of takerAsset being bid on by maker. Must be greater than 0.
uint256 takerAssetAmount;
// Fee paid to feeRecipient by maker when order is filled.
uint256 makerFee;
// Fee paid to feeRecipient by taker when order is filled.
uint256 takerFee;
// Timestamp in seconds at which order expires.
uint256 expirationTimeSeconds;
// Arbitrary number to facilitate uniqueness of the order's hash.
uint256 salt;
// Encoded data that can be decoded by a specified proxy contract when transferring makerAsset.
// The leading bytes4 references the id of the asset proxy.
bytes makerAssetData;
// Encoded data that can be decoded by a specified proxy contract when transferring takerAsset.
// The leading bytes4 references the id of the asset proxy.
bytes takerAssetData;
// Encoded data that can be decoded by a specified proxy contract when transferring makerFeeAsset.
// The leading bytes4 references the id of the asset proxy.
bytes makerFeeAssetData;
// Encoded data that can be decoded by a specified proxy contract when transferring takerFeeAsset.
// The leading bytes4 references the id of the asset proxy.
bytes takerFeeAssetData;
}
/// @dev V3 `fillOrder()` results.`
struct FillResults {
// Total amount of makerAsset(s) filled.
uint256 makerAssetFilledAmount;
// Total amount of takerAsset(s) filled.
uint256 takerAssetFilledAmount;
// Total amount of fees paid by maker(s) to feeRecipient(s).
uint256 makerFeePaid;
// Total amount of fees paid by taker to feeRecipients(s).
uint256 takerFeePaid;
// Total amount of fees paid by taker to the staking contract.
uint256 protocolFeePaid;
}
/// @dev Fills the input order.
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return fillResults Amounts filled and fees paid by maker and taker.
function fillOrder(
Order calldata order,
uint256 takerAssetFillAmount,
bytes calldata signature
)
external
payable
returns (FillResults memory fillResults);
/// @dev Returns the protocolFeeMultiplier
/// @return multiplier The multiplier for protocol fees.
function protocolFeeMultiplier()
external
view
returns (uint256 multiplier);
/// @dev Gets an asset proxy.
/// @param assetProxyId Id of the asset proxy.
/// @return proxyAddress The asset proxy registered to assetProxyId.
/// Returns 0x0 if no proxy is registered.
function getAssetProxy(bytes4 assetProxyId)
external
view
returns (address proxyAddress);
function EIP712_EXCHANGE_DOMAIN_HASH()
external
view
returns (bytes32 domainHash);
}

View File

@@ -1,38 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
interface IGasToken {
/// @dev Frees up to `value` sub-tokens
/// @param value The amount of tokens to free
/// @return freed How many tokens were freed
function freeUpTo(uint256 value) external returns (uint256 freed);
/// @dev Frees up to `value` sub-tokens owned by `from`
/// @param from The owner of tokens to spend
/// @param value The amount of tokens to free
/// @return freed How many tokens were freed
function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);
/// @dev Mints `value` amount of tokens
/// @param value The amount of tokens to mint
function mint(uint256 value) external;
}

View File

@@ -1,168 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
import "./IExchange.sol";
library LibOrderHash {
using LibOrderHash for IExchange.Order;
// Hash for the EIP712 Order Schema:
// keccak256(abi.encodePacked(
// "Order(",
// "address makerAddress,",
// "address takerAddress,",
// "address feeRecipientAddress,",
// "address senderAddress,",
// "uint256 makerAssetAmount,",
// "uint256 takerAssetAmount,",
// "uint256 makerFee,",
// "uint256 takerFee,",
// "uint256 expirationTimeSeconds,",
// "uint256 salt,",
// "bytes makerAssetData,",
// "bytes takerAssetData,",
// "bytes makerFeeAssetData,",
// "bytes takerFeeAssetData",
// ")"
// ))
bytes32 constant internal _EIP712_ORDER_SCHEMA_HASH =
0xf80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534;
/// @dev Calculates the EIP712 typed data hash of an order with a given domain separator.
/// @param order The order structure.
/// @param eip712ExchangeDomainHash Domain hash for the Exchange.
/// @return orderHash EIP712 typed data hash of the order.
function getTypedDataHash(IExchange.Order memory order, bytes32 eip712ExchangeDomainHash)
internal
pure
returns (bytes32 orderHash)
{
orderHash = _hashEIP712Message(
eip712ExchangeDomainHash,
order.getStructHash()
);
return orderHash;
}
/// @dev Calculates EIP712 hash of the order struct.
/// @param order The order structure.
/// @return result EIP712 hash of the order struct.
function getStructHash(IExchange.Order memory order)
internal
pure
returns (bytes32 result)
{
bytes32 schemaHash = _EIP712_ORDER_SCHEMA_HASH;
bytes memory makerAssetData = order.makerAssetData;
bytes memory takerAssetData = order.takerAssetData;
bytes memory makerFeeAssetData = order.makerFeeAssetData;
bytes memory takerFeeAssetData = order.takerFeeAssetData;
// Assembly for more efficiently computing:
// keccak256(abi.encodePacked(
// EIP712_ORDER_SCHEMA_HASH,
// uint256(order.makerAddress),
// uint256(order.takerAddress),
// uint256(order.feeRecipientAddress),
// uint256(order.senderAddress),
// order.makerAssetAmount,
// order.takerAssetAmount,
// order.makerFee,
// order.takerFee,
// order.expirationTimeSeconds,
// order.salt,
// keccak256(order.makerAssetData),
// keccak256(order.takerAssetData),
// keccak256(order.makerFeeAssetData),
// keccak256(order.takerFeeAssetData)
// ));
assembly {
// Assert order offset (this is an internal error that should never be triggered)
if lt(order, 32) {
invalid()
}
// Calculate memory addresses that will be swapped out before hashing
let pos1 := sub(order, 32)
let pos2 := add(order, 320)
let pos3 := add(order, 352)
let pos4 := add(order, 384)
let pos5 := add(order, 416)
// Backup
let temp1 := mload(pos1)
let temp2 := mload(pos2)
let temp3 := mload(pos3)
let temp4 := mload(pos4)
let temp5 := mload(pos5)
// Hash in place
mstore(pos1, schemaHash)
mstore(pos2, keccak256(add(makerAssetData, 32), mload(makerAssetData))) // store hash of makerAssetData
mstore(pos3, keccak256(add(takerAssetData, 32), mload(takerAssetData))) // store hash of takerAssetData
mstore(pos4, keccak256(add(makerFeeAssetData, 32), mload(makerFeeAssetData))) // store hash of makerFeeAssetData
mstore(pos5, keccak256(add(takerFeeAssetData, 32), mload(takerFeeAssetData))) // store hash of takerFeeAssetData
result := keccak256(pos1, 480)
// Restore
mstore(pos1, temp1)
mstore(pos2, temp2)
mstore(pos3, temp3)
mstore(pos4, temp4)
mstore(pos5, temp5)
}
return result;
}
/// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.
/// @param eip712DomainHash Hash of the domain domain separator data, computed
/// with getDomainHash().
/// @param hashStruct The EIP712 hash struct.
/// @return result EIP712 hash applied to the given EIP712 Domain.
function _hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)
internal
pure
returns (bytes32 result)
{
// Assembly for more efficient computing:
// keccak256(abi.encodePacked(
// EIP191_HEADER,
// EIP712_DOMAIN_HASH,
// hashStruct
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
mstore(add(memPtr, 34), hashStruct) // Hash of struct
// Compute hash
result := keccak256(memPtr, 66)
}
return result;
}
}

View File

@@ -27,39 +27,25 @@ import "./TestMintableERC20Token.sol";
contract TestFillQuoteTransformerBridge {
struct FillBehavior {
// Scaling for maker assets minted, in 1e18.
uint256 makerAssetMintRatio;
uint256 amount;
}
uint256 private constant REVERT_AMOUNT = 0xdeadbeef;
function sellTokenForToken(
address takerToken,
address /* takerToken */,
address makerToken,
address recipient,
uint256 minBuyAmount,
uint256 /* minBuyAmount */,
bytes calldata auxiliaryData
)
external
returns (uint256 boughtAmount)
{
FillBehavior memory behavior = abi.decode(auxiliaryData, (FillBehavior));
boughtAmount = LibMathV06.getPartialAmountFloor(
behavior.makerAssetMintRatio,
1e18,
behavior.amount
);
boughtAmount = abi.decode(auxiliaryData, (uint256));
if (REVERT_AMOUNT == boughtAmount) {
revert("REVERT_AMOUNT");
}
TestMintableERC20Token(makerToken).mint(
recipient,
boughtAmount
);
}
function encodeBehaviorData(FillBehavior calldata behavior)
external
pure
returns (bytes memory encoded)
{
return abi.encode(behavior);
}
}

View File

@@ -23,106 +23,109 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../src/vendor/v3/IExchange.sol";
import "./TestMintableERC20Token.sol";
import "../src/features/libs/LibNativeOrder.sol";
import "../src/features/libs/LibSignature.sol";
contract TestFillQuoteTransformerExchange {
struct FillBehavior {
// How much of the order is filled, in taker asset amount.
uint256 filledTakerAssetAmount;
// Scaling for maker assets minted, in 1e18.
uint256 makerAssetMintRatio;
}
bytes32 public constant EIP712_EXCHANGE_DOMAIN_HASH = 0xaa81d881b1adbbf115e15b849cb9cdc643cad3c6a90f30eb505954af943247e6;
uint256 private constant REVERT_AMOUNT = 0xdeadbeef;
uint256 private constant PROTOCOL_FEE_MULTIPLIER = 1337;
using LibSafeMathV06 for uint256;
function fillOrder(
IExchange.Order calldata order,
uint256 takerAssetFillAmount,
bytes calldata signature
function fillLimitOrder(
LibNativeOrder.LimitOrder calldata order,
LibSignature.Signature calldata signature,
uint128 takerTokenFillAmount
)
external
payable
returns (IExchange.FillResults memory fillResults)
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
require(
signature.length != 0,
"TestFillQuoteTransformerExchange/INVALID_SIGNATURE"
);
// The signature is the ABI-encoded FillBehavior data.
FillBehavior memory behavior = abi.decode(signature, (FillBehavior));
// The r field of the signature is the pre-filled amount.
uint128 takerTokenPreFilledAmount = uint128(uint256(signature.r));
if (REVERT_AMOUNT == takerTokenPreFilledAmount) {
revert("REVERT_AMOUNT");
}
if (takerTokenPreFilledAmount >= order.takerAmount) {
revert('FILLED');
}
uint256 protocolFee = PROTOCOL_FEE_MULTIPLIER * tx.gasprice;
require(
msg.value == protocolFee,
"TestFillQuoteTransformerExchange/INSUFFICIENT_PROTOCOL_FEE"
);
// Return excess protocol fee.
msg.sender.transfer(msg.value - protocolFee);
takerTokenFilledAmount = LibSafeMathV06.min128(
order.takerAmount - takerTokenPreFilledAmount,
takerTokenFillAmount
);
// Take taker tokens.
TestMintableERC20Token takerToken = _getTokenFromAssetData(order.takerAssetData);
takerAssetFillAmount = LibSafeMathV06.min256(
order.takerAssetAmount.safeSub(behavior.filledTakerAssetAmount),
takerAssetFillAmount
order.takerToken.transferFrom(
msg.sender,
order.maker,
takerTokenFilledAmount
);
require(
takerToken.getSpendableAmount(msg.sender, address(this)) >= takerAssetFillAmount,
"TestFillQuoteTransformerExchange/INSUFFICIENT_TAKER_FUNDS"
);
takerToken.transferFrom(msg.sender, order.makerAddress, takerAssetFillAmount);
// Mint maker tokens.
uint256 makerAssetFilledAmount = LibMathV06.getPartialAmountFloor(
takerAssetFillAmount,
order.takerAssetAmount,
order.makerAssetAmount
);
TestMintableERC20Token makerToken = _getTokenFromAssetData(order.makerAssetData);
makerToken.mint(
msg.sender,
LibMathV06.getPartialAmountFloor(
behavior.makerAssetMintRatio,
1e18,
makerAssetFilledAmount
)
makerTokenFilledAmount = LibSafeMathV06.safeDowncastToUint128(
uint256(takerTokenFilledAmount)
* uint256(order.makerAmount)
/ uint256(order.takerAmount)
);
TestMintableERC20Token(address(order.makerToken))
.mint(msg.sender, makerTokenFilledAmount);
// Take taker fee.
TestMintableERC20Token takerFeeToken = _getTokenFromAssetData(order.takerFeeAssetData);
uint256 takerFee = LibMathV06.getPartialAmountFloor(
takerAssetFillAmount,
order.takerAssetAmount,
order.takerFee
// Take taker token fee.
uint128 takerFee = LibSafeMathV06.safeDowncastToUint128(
uint256(takerTokenFilledAmount)
* uint256(order.takerTokenFeeAmount)
/ uint256(order.takerAmount)
);
require(
takerFeeToken.getSpendableAmount(msg.sender, address(this)) >= takerFee,
"TestFillQuoteTransformerExchange/INSUFFICIENT_TAKER_FEE_FUNDS"
);
takerFeeToken.transferFrom(msg.sender, order.feeRecipientAddress, takerFee);
fillResults.makerAssetFilledAmount = makerAssetFilledAmount;
fillResults.takerAssetFilledAmount = takerAssetFillAmount;
fillResults.makerFeePaid = uint256(-1);
fillResults.takerFeePaid = takerFee;
fillResults.protocolFeePaid = protocolFee;
order.takerToken.transferFrom(msg.sender, order.feeRecipient, takerFee);
}
function encodeBehaviorData(FillBehavior calldata behavior)
function fillRfqOrder(
LibNativeOrder.RfqOrder calldata order,
LibSignature.Signature calldata signature,
uint128 takerTokenFillAmount
)
external
pure
returns (bytes memory encoded)
payable
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
return abi.encode(behavior);
// The r field of the signature is the pre-filled amount.
uint128 takerTokenPreFilledAmount = uint128(uint256(signature.r));
if (REVERT_AMOUNT == takerTokenPreFilledAmount) {
revert("REVERT_AMOUNT");
}
if (takerTokenPreFilledAmount >= order.takerAmount) {
revert('FILLED');
}
takerTokenFilledAmount = LibSafeMathV06.min128(
order.takerAmount - takerTokenPreFilledAmount,
takerTokenFillAmount
);
// Take taker tokens.
order.takerToken.transferFrom(
msg.sender,
order.maker,
takerTokenFilledAmount
);
// Mint maker tokens.
makerTokenFilledAmount = LibSafeMathV06.safeDowncastToUint128(
uint256(takerTokenFilledAmount)
* uint256(order.makerAmount)
/ uint256(order.takerAmount)
);
TestMintableERC20Token(address(order.makerToken))
.mint(msg.sender, makerTokenFilledAmount);
}
function protocolFeeMultiplier()
function getProtocolFeeMultiplier()
external
pure
returns (uint256)
@@ -130,19 +133,11 @@ contract TestFillQuoteTransformerExchange {
return PROTOCOL_FEE_MULTIPLIER;
}
function getAssetProxy(bytes4)
function getLimitOrderHash(LibNativeOrder.LimitOrder calldata order)
external
view
returns (address)
{
return address(this);
}
function _getTokenFromAssetData(bytes memory assetData)
private
pure
returns (TestMintableERC20Token token)
returns (bytes32)
{
return TestMintableERC20Token(LibBytesV06.readAddress(assetData, 16));
return bytes32(order.salt);
}
}

View File

@@ -65,14 +65,13 @@ contract TestLiquidityProvider {
/// @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
bytes calldata // auxiliaryData
)
external
returns (uint256 boughtAmount)
@@ -91,13 +90,12 @@ contract TestLiquidityProvider {
/// @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
bytes calldata // auxiliaryData
)
external
returns (uint256 boughtAmount)
@@ -115,13 +113,12 @@ contract TestLiquidityProvider {
/// @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
bytes calldata // auxiliaryData
)
external
returns (uint256 boughtAmount)

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-zero-ex",
"version": "0.18.1",
"version": "0.18.2",
"engines": {
"node": ">=6.12"
},
@@ -43,7 +43,7 @@
"config": {
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|BridgeSource|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
},
"repository": {
"type": "git",
@@ -56,12 +56,12 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contract-addresses": "^5.9.0",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contract-addresses": "^5.10.0",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -83,7 +83,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/protocol-utils": "^1.1.5",
"@0x/protocol-utils": "^1.2.0",
"@0x/subproviders": "^6.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -9,6 +9,7 @@ import * as AffiliateFeeTransformer from '../test/generated-artifacts/AffiliateF
import * as AllowanceTarget from '../test/generated-artifacts/AllowanceTarget.json';
import * as BootstrapFeature from '../test/generated-artifacts/BootstrapFeature.json';
import * as BridgeAdapter from '../test/generated-artifacts/BridgeAdapter.json';
import * as BridgeSource from '../test/generated-artifacts/BridgeSource.json';
import * as FeeCollector from '../test/generated-artifacts/FeeCollector.json';
import * as FeeCollectorController from '../test/generated-artifacts/FeeCollectorController.json';
import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json';
@@ -24,10 +25,8 @@ import * as IBootstrapFeature from '../test/generated-artifacts/IBootstrapFeatur
import * as IBridgeAdapter from '../test/generated-artifacts/IBridgeAdapter.json';
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json';
import * as IExchange from '../test/generated-artifacts/IExchange.json';
import * as IFeature from '../test/generated-artifacts/IFeature.json';
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';
@@ -53,7 +52,6 @@ import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json';
import * as LibNativeOrder from '../test/generated-artifacts/LibNativeOrder.json';
import * as LibNativeOrdersRichErrors from '../test/generated-artifacts/LibNativeOrdersRichErrors.json';
import * as LibNativeOrdersStorage from '../test/generated-artifacts/LibNativeOrdersStorage.json';
import * as LibOrderHash from '../test/generated-artifacts/LibOrderHash.json';
import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json';
import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json';
import * as LibProxyRichErrors from '../test/generated-artifacts/LibProxyRichErrors.json';
@@ -73,7 +71,6 @@ import * as LiquidityProviderFeature from '../test/generated-artifacts/Liquidity
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';
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
@@ -211,8 +208,8 @@ export const artifacts = {
Transformer: Transformer as ContractArtifact,
WethTransformer: WethTransformer as ContractArtifact,
BridgeAdapter: BridgeAdapter as ContractArtifact,
BridgeSource: BridgeSource as ContractArtifact,
IBridgeAdapter: IBridgeAdapter as ContractArtifact,
MixinAdapterAddresses: MixinAdapterAddresses as ContractArtifact,
MixinBalancer: MixinBalancer as ContractArtifact,
MixinBancor: MixinBancor as ContractArtifact,
MixinCoFiX: MixinCoFiX as ContractArtifact,
@@ -230,10 +227,7 @@ export const artifacts = {
MixinZeroExBridge: MixinZeroExBridge as ContractArtifact,
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
IExchange: IExchange as ContractArtifact,
IGasToken: IGasToken as ContractArtifact,
IStaking: IStaking as ContractArtifact,
LibOrderHash: LibOrderHash as ContractArtifact,
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
TestBridge: TestBridge as ContractArtifact,
TestCallTarget: TestCallTarget as ContractArtifact,

View File

@@ -7,6 +7,7 @@ export * from '../test/generated-wrappers/affiliate_fee_transformer';
export * from '../test/generated-wrappers/allowance_target';
export * from '../test/generated-wrappers/bootstrap_feature';
export * from '../test/generated-wrappers/bridge_adapter';
export * from '../test/generated-wrappers/bridge_source';
export * from '../test/generated-wrappers/fee_collector';
export * from '../test/generated-wrappers/fee_collector_controller';
export * from '../test/generated-wrappers/fill_quote_transformer';
@@ -22,10 +23,8 @@ export * from '../test/generated-wrappers/i_bootstrap_feature';
export * from '../test/generated-wrappers/i_bridge_adapter';
export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_erc20_transformer';
export * from '../test/generated-wrappers/i_exchange';
export * from '../test/generated-wrappers/i_feature';
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';
@@ -51,7 +50,6 @@ export * from '../test/generated-wrappers/lib_migrate';
export * from '../test/generated-wrappers/lib_native_order';
export * from '../test/generated-wrappers/lib_native_orders_rich_errors';
export * from '../test/generated-wrappers/lib_native_orders_storage';
export * from '../test/generated-wrappers/lib_order_hash';
export * from '../test/generated-wrappers/lib_ownable_rich_errors';
export * from '../test/generated-wrappers/lib_ownable_storage';
export * from '../test/generated-wrappers/lib_proxy_rich_errors';
@@ -71,7 +69,6 @@ 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';
export * from '../test/generated-wrappers/mixin_balancer';
export * from '../test/generated-wrappers/mixin_bancor';
export * from '../test/generated-wrappers/mixin_co_fi_x';

View File

@@ -35,6 +35,7 @@
"test/generated-artifacts/AllowanceTarget.json",
"test/generated-artifacts/BootstrapFeature.json",
"test/generated-artifacts/BridgeAdapter.json",
"test/generated-artifacts/BridgeSource.json",
"test/generated-artifacts/FeeCollector.json",
"test/generated-artifacts/FeeCollectorController.json",
"test/generated-artifacts/FillQuoteTransformer.json",
@@ -50,10 +51,8 @@
"test/generated-artifacts/IBridgeAdapter.json",
"test/generated-artifacts/IERC20Bridge.json",
"test/generated-artifacts/IERC20Transformer.json",
"test/generated-artifacts/IExchange.json",
"test/generated-artifacts/IFeature.json",
"test/generated-artifacts/IFlashWallet.json",
"test/generated-artifacts/IGasToken.json",
"test/generated-artifacts/ILiquidityProvider.json",
"test/generated-artifacts/ILiquidityProviderFeature.json",
"test/generated-artifacts/ILiquidityProviderSandbox.json",
@@ -79,7 +78,6 @@
"test/generated-artifacts/LibNativeOrder.json",
"test/generated-artifacts/LibNativeOrdersRichErrors.json",
"test/generated-artifacts/LibNativeOrdersStorage.json",
"test/generated-artifacts/LibOrderHash.json",
"test/generated-artifacts/LibOwnableRichErrors.json",
"test/generated-artifacts/LibOwnableStorage.json",
"test/generated-artifacts/LibProxyRichErrors.json",
@@ -99,7 +97,6 @@
"test/generated-artifacts/LiquidityProviderSandbox.json",
"test/generated-artifacts/LogMetadataTransformer.json",
"test/generated-artifacts/MetaTransactionsFeature.json",
"test/generated-artifacts/MixinAdapterAddresses.json",
"test/generated-artifacts/MixinBalancer.json",
"test/generated-artifacts/MixinBancor.json",
"test/generated-artifacts/MixinCoFiX.json",

View File

@@ -7,43 +7,60 @@ Releases
.. note::
Come out and vote! The community vote for Protocol V4 goes live on Saturday, January 16 2021. Cast your vote `HERE <https://0x.org/zrx/vote/zeip-82>`_!
These releases are approved by the 0x Community. Come out and vote `HERE <https://0x.org/zrx/vote/>`_!
This page outlines upcoming releases and expected changes.
.. table::
:widths: 20 50 10 10 10
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| **Name** | **Overview** | **Est Release Date** | **Status** | **Additional** |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `big-pantsuit-energy`_ | Patch batch ```getOrderRelevantState()``` functions | 01/25/21 | Timelock | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `Squire`_ | Aggregation for `V4 Orders <../basics/orders.html>`_ | TBA | Development | Depends on AssetSwapper / 0x API Upgrade |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `Babooshka`_ | Connect Exchange Proxy to Staking | 02/08/21 | Vote | Requires community vote |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| *The following releases have been deployed* | | | | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `Panettone`_ | Minor patches from `Consensys Audit <./audits.html>`_ | 01/12/21 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/LOG.md#panettone>`_ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `cyberpants2077`_ | `V4 Orders <../basics/orders.html>`_ | 01/05/21 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/LOG.md#cyberpants2077>`_ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `Hot-Pants`_ | Remove calldata signing / DeFi Saver Fix / Allowance on Proxy | 12/07/20 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/LOG.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `Plop`_ | PLP VIP | 12/01/20 | Deployed | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| `Tinker`_ | Set allowances directly on Exchange Proxy | 11/12/20 | Deployed | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-----------------------------------------------------------------------------------------------------------------------------+
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| **Name** | **Overview** | **Est Release Date** | **Status** | **Additional** |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Amaretto`_ | Protocol 4.1: Efficiency + Batch Fills | 03/15/21 | Development | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| *The following releases have been deployed* | | | | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Babooshka`_ | Connect Exchange Proxy to Staking | 02/08/21 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/9_babooshka.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Squire`_ | Aggregation for `V4 Orders <../basics/orders.html>`_ | 02/04/21 | Deployed | N/A |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `big-pantsuit-energy`_ | Patch batch ```getOrderRelevantState()``` functions | 01/25/21 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/8_big-pantsuit-energy.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Panettone`_ | Minor patches from `Consensys Audit <./audits.html>`_ | 01/12/21 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/7_panettone.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `cyberpants2077`_ | `V4 Orders <../basics/orders.html>`_ | 01/05/21 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/6_cyberpants2077.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Hot-Pants`_ | Remove calldata signing / DeFi Saver Fix / Allowance on Proxy | 12/07/20 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/5_hot_pants.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Plop`_ | PLP VIP | 12/01/20 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/4_plop.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Tinker`_ | Set allowances directly on Exchange Proxy | 11/12/20 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/3_tinker.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Elphaba`_ | Meta-Transactions + Uniswap VIP | | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/2_elphaba.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Champagne-Problems`_ | Signed Calldata | | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/1_champagne_problems.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
Upcoming
========
big-pantsuit-energy
-------------------
Amaretto
--------
- Swallow reverts in `batchGetRfqOrderRelevantStates()` and `batchGetLimitOrderRelevantStates()` functions.
- RFQ VIP (fallback to DEX if RFQ orders is unfillable)
- Batch fills for native orders
- Mooniswap VIP
- Curve / Swerve VIP (via PLP Sandbox)
Past
=====
Babooshka
----------
- Register the 0x Exchange Proxy with the Staking Proxy, allowing protocol fees from V4 Orders to be paid to Staking Pools.
Squire
@@ -52,15 +69,10 @@ Squire
- Deploy updated `FillQuoteTransformer <../architecture/transformers.html>`_, which can fill `V4 Orders <../basics/orders.html>`_. This transformer will no longer call Exchange V3.
- This will replace the `ERC20BridgeTransfer Event <../basics/events.html#erc20bridgetransfer>`_
big-pantsuit-energy
-------------------
Babooshka
----------
- Register the 0x Exchange Proxy with the Staking Proxy, allowing protocol fees from V4 Orders to be paid to Staking Pools.
Past
=====
- Swallow reverts in `batchGetRfqOrderRelevantStates()` and `batchGetLimitOrderRelevantStates()` functions.
Panettone
----------
@@ -97,3 +109,17 @@ Tinker
This release was partially rolled back due to breaking allowances for some `Exceptional ERC20 Tokens <./exceptional_erc20s.html>`_. These features were fixed and re-deployed in the Hot-Pants release, above.
- Upgrade any features that transfer user funds to use allowances on the Proxy contract. Transfers will still fallback to the Allowance Target, but integrators will get reduced transaction costs from setting their allowance on the Proxy. This involves redeploying the following `Features <../architecture/features.html>`_: ``MetaTransactionsFeature``, ``TransformERC20Feature``, ``UniswapFeature``.
Elphaba
-------
- Updates for Meta-Transactions Feature
- Uniswap VIP for efficient fills through Uniswap.
Champagne-Problems
------------------
- Signed Calldata for Meta-Transactions

View File

@@ -123,19 +123,27 @@ In both cases, the ``@0x/protocol-utils`` package simplifies generating these si
takerToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
... // Other fields
});
// Generate an EIP712 signature
const signature = await order.eip712SignTypedDataWithProviderAsync(
// Generate an EthSign signature with a provider.
const signature = await order.getSignatureWithProviderAsync(
web3.currentProvider,
makerAddress,
);
// Generate an EthSign signature
const signature = await order.ethSignHashWithProviderAsync(
// Generate an EthSign signature with a private key.
const signature = await order.getSignatureWithKey(
'0x123456...', // Maker's 32-byte private key, in hex.
);
// Generate an EIP712 signature with a provider (e.g., metamask).
const signature = await order.getSignatureWithProviderAsync(
web3.currentProvider,
makerAddress,
utils.SignatureType.EIP712,
);
// Generate an EIP712 signature with a private key.
const signature = await order.getSignatureWithKey(
'0x123456...', // Maker's 32-byte private key, in hex.
utils.SignatureType.EIP712,
);
The Orderbook
The Orderbook
=======================
Orders are shared through a decentralized and permissionless network, called `0x Mesh <https://0x.org/mesh>`_. The simplest way to post and discover orders is through `0x API <https://0x.org/api>`_. See `this guide <https://0x.org/docs/guides/market-making-on-0x>`_ tailored for Market Makers.
@@ -167,4 +175,4 @@ A ``RFQOrder`` should be serialized to JSON as following:
"s": string,
"r": string,
}
}
}

View File

@@ -1,4 +1,30 @@
[
{
"version": "6.0.0",
"changes": [
{
"note": "Pull top 250 Balancer pairs on initialization",
"pr": 113
},
{
"note": "Support v4 `RFQ` and `Limit` orders",
"pr": 113
},
{
"note": "Refactor to consume latest `FillQuoteTransformer`",
"pr": 113
},
{
"note": "Enable `fillData` for all sources, no longer optional",
"pr": 113
},
{
"note": "Support `tx.origin` in RFQT quote requestor",
"pr": 113
}
],
"timestamp": 1612950500
},
{
"version": "5.8.2",
"changes": [

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v6.0.0 - _February 10, 2021_
* Pull top 250 Balancer pairs on initialization (#113)
* Support v4 `RFQ` and `Limit` orders (#113)
* Refactor to consume latest `FillQuoteTransformer` (#113)
* Enable `fillData` for all sources, no longer optional (#113)
* Support `tx.origin` in RFQT quote requestor (#113)
## v5.8.2 - _January 28, 2021_
* Fix error when Multihop data is not present (#80)

View File

@@ -58,6 +58,39 @@ contract BalanceChecker {
return addrBalances;
}
/*
Check the token balances of wallet-token pairs with a spender contract for an allowance check.
Pass 0xeee... as a "token" address to get ETH balance.
Possible error throws:
- extremely large arrays for user and or tokens (gas cost too high)
Returns a one-dimensional that's user.length long. It is the lesser of balance and allowance
*/
function getMinOfBalancesOrAllowances(address[] calldata users, address[] calldata tokens, address spender) external view returns (uint256[] memory) {
// make sure the users array and tokens array are of equal length
require(users.length == tokens.length, "users array is a different length than the tokens array");
uint256[] memory addrBalances = new uint256[](users.length);
for(uint i = 0; i < users.length; i++) {
if (tokens[i] != address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)) {
uint256 balance;
uint256 allowance;
balance = IToken(tokens[i]).balanceOf(users[i]);
allowance = IToken(tokens[i]).allowance(users[i], spender);
if (allowance < balance) {
addrBalances[i] = allowance;
} else {
addrBalances[i] = balance;
}
} else {
addrBalances[i] = users[i].balance; // ETH balance
}
}
return addrBalances;
}
/*
Check the allowances of an array of owner-spender-tokens

View File

@@ -36,6 +36,7 @@ import "./SushiSwapSampler.sol";
import "./TwoHopSampler.sol";
import "./UniswapSampler.sol";
import "./UniswapV2Sampler.sol";
import "./UtilitySampler.sol";
contract ERC20BridgeSampler is
@@ -54,7 +55,8 @@ contract ERC20BridgeSampler is
SushiSwapSampler,
TwoHopSampler,
UniswapSampler,
UniswapV2Sampler
UniswapV2Sampler,
UtilitySampler
{
struct CallResults {

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -28,126 +28,118 @@ import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
interface IExchange {
/// @dev V3 Order structure.
struct Order {
// Address that created the order.
address makerAddress;
// Address that is allowed to fill the order.
// If set to 0, any address is allowed to fill the order.
address takerAddress;
// Address that will recieve fees when order is filled.
address feeRecipientAddress;
// Address that is allowed to call Exchange contract methods that affect this order.
// If set to 0, any address is allowed to call these methods.
address senderAddress;
// Amount of makerAsset being offered by maker. Must be greater than 0.
uint256 makerAssetAmount;
// Amount of takerAsset being bid on by maker. Must be greater than 0.
uint256 takerAssetAmount;
// Fee paid to feeRecipient by maker when order is filled.
uint256 makerFee;
// Fee paid to feeRecipient by taker when order is filled.
uint256 takerFee;
// Timestamp in seconds at which order expires.
uint256 expirationTimeSeconds;
// Arbitrary number to facilitate uniqueness of the order's hash.
uint256 salt;
// Encoded data that can be decoded by a specified proxy contract when transferring makerAsset.
// The leading bytes4 references the id of the asset proxy.
bytes makerAssetData;
// Encoded data that can be decoded by a specified proxy contract when transferring takerAsset.
// The leading bytes4 references the id of the asset proxy.
bytes takerAssetData;
// Encoded data that can be decoded by a specified proxy contract when transferring makerFeeAsset.
// The leading bytes4 references the id of the asset proxy.
bytes makerFeeAssetData;
// Encoded data that can be decoded by a specified proxy contract when transferring takerFeeAsset.
// The leading bytes4 references the id of the asset proxy.
bytes takerFeeAssetData;
}
// A valid order remains fillable until it is expired, fully filled, or cancelled.
// An order's status is unaffected by external factors, like account balances.
enum OrderStatus {
INVALID, // Default value
INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
FILLABLE, // Order is fillable
EXPIRED, // Order has already expired
FULLY_FILLED, // Order is fully filled
CANCELLED // Order has been cancelled
INVALID,
FILLABLE,
FILLED,
CANCELLED,
EXPIRED
}
/// @dev Order information returned by `getOrderInfo()`.
/// @dev A standard OTC or OO limit order.
struct LimitOrder {
IERC20TokenV06 makerToken;
IERC20TokenV06 takerToken;
uint128 makerAmount;
uint128 takerAmount;
uint128 takerTokenFeeAmount;
address maker;
address taker;
address sender;
address feeRecipient;
bytes32 pool;
uint64 expiry;
uint256 salt;
}
/// @dev An RFQ limit order.
struct RfqOrder {
IERC20TokenV06 makerToken;
IERC20TokenV06 takerToken;
uint128 makerAmount;
uint128 takerAmount;
address maker;
address taker;
address txOrigin;
bytes32 pool;
uint64 expiry;
uint256 salt;
}
/// @dev Info on a limit or RFQ order.
struct OrderInfo {
OrderStatus orderStatus; // Status that describes order's validity and fillability.
bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash).
uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
bytes32 orderHash;
OrderStatus status;
uint128 takerTokenFilledAmount;
}
/// @dev Gets information about an order: status, hash, and amount filled.
/// @param order Order to gather information on.
/// @return orderInfo Information about the order and its state.
function getOrderInfo(IExchange.Order calldata order)
/// @dev Allowed signature types.
enum SignatureType {
ILLEGAL,
INVALID,
EIP712,
ETHSIGN
}
/// @dev Encoded EC signature.
struct Signature {
// How to validate the signature.
SignatureType signatureType;
// EC Signature data.
uint8 v;
// EC Signature data.
bytes32 r;
// EC Signature data.
bytes32 s;
}
/// @dev Get the order info for a limit order.
/// @param order The limit order.
/// @return orderInfo Info about the order.
function getLimitOrderInfo(LimitOrder memory order)
external
view
returns (IExchange.OrderInfo memory orderInfo);
returns (OrderInfo memory orderInfo);
/// @dev Verifies that a hash has been signed by the given signer.
/// @param hash Any 32-byte hash.
/// @param signature Proof that the hash has been signed by signer.
/// @return isValid `true` if the signature is valid for the given hash and signer.
function isValidHashSignature(
bytes32 hash,
address signerAddress,
bytes calldata signature
/// @dev Get order info, fillable amount, and signature validity for a limit order.
/// Fillable amount is determined using balances and allowances of the maker.
/// @param order The limit order.
/// @param signature The order signature.
/// @return orderInfo Info about the order.
/// @return actualFillableTakerTokenAmount How much of the order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValid Whether the signature is valid.
function getLimitOrderRelevantState(
LimitOrder memory order,
Signature calldata signature
)
external
view
returns (bool isValid);
/// @dev Gets an asset proxy.
/// @param assetProxyId Id of the asset proxy.
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
function getAssetProxy(bytes4 assetProxyId)
external
view
returns (address);
returns (
OrderInfo memory orderInfo,
uint128 actualFillableTakerTokenAmount,
bool isSignatureValid
);
}
contract NativeOrderSampler {
using LibSafeMathV06 for uint256;
using LibBytesV06 for bytes;
/// @dev The Exchange ERC20Proxy ID.
bytes4 private constant ERC20_ASSET_PROXY_ID = 0xf47261b0;
/// @dev Gas limit for calls to `getOrderFillableTakerAmount()`.
uint256 constant internal DEFAULT_CALL_GAS = 200e3; // 200k
function getTokenDecimals(
address makerTokenAddress,
address takerTokenAddress
)
public
view
returns (uint256, uint256)
{
uint256 fromTokenDecimals = LibERC20TokenV06.compatDecimals(IERC20TokenV06(makerTokenAddress));
uint256 toTokenDecimals = LibERC20TokenV06.compatDecimals(IERC20TokenV06(takerTokenAddress));
return (fromTokenDecimals, toTokenDecimals);
}
/// @dev Queries the fillable taker asset amounts of native orders.
/// Effectively ignores orders that have empty signatures or
/// maker/taker asset amounts (returning 0).
/// @param orders Native orders to query.
/// @param orders Native limit orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param exchange The V3 exchange.
/// @param exchange The V4 exchange.
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
/// by each order in `orders`.
function getOrderFillableTakerAssetAmounts(
IExchange.Order[] memory orders,
bytes[] memory orderSignatures,
function getLimitOrderFillableTakerAssetAmounts(
IExchange.LimitOrder[] memory orders,
IExchange.Signature[] memory orderSignatures,
IExchange exchange
)
public
@@ -157,7 +149,7 @@ contract NativeOrderSampler {
orderFillableTakerAssetAmounts = new uint256[](orders.length);
for (uint256 i = 0; i != orders.length; i++) {
try
this.getOrderFillableTakerAmount
this.getLimitOrderFillableTakerAmount
{gas: DEFAULT_CALL_GAS}
(
orders[i],
@@ -178,19 +170,19 @@ contract NativeOrderSampler {
/// Effectively ignores orders that have empty signatures or
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param exchange The V3 exchange.
/// @param exchange The V4 exchange.
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
/// by each order in `orders`.
function getOrderFillableMakerAssetAmounts(
IExchange.Order[] memory orders,
bytes[] memory orderSignatures,
function getLimitOrderFillableMakerAssetAmounts(
IExchange.LimitOrder[] memory orders,
IExchange.Signature[] memory orderSignatures,
IExchange exchange
)
public
view
returns (uint256[] memory orderFillableMakerAssetAmounts)
{
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
orderFillableMakerAssetAmounts = getLimitOrderFillableTakerAssetAmounts(
orders,
orderSignatures,
exchange
@@ -201,8 +193,8 @@ contract NativeOrderSampler {
if (orderFillableMakerAssetAmounts[i] != 0) {
orderFillableMakerAssetAmounts[i] = LibMathV06.getPartialAmountCeil(
orderFillableMakerAssetAmounts[i],
orders[i].takerAssetAmount,
orders[i].makerAssetAmount
orders[i].takerAmount,
orders[i].makerAmount
);
}
}
@@ -210,9 +202,9 @@ contract NativeOrderSampler {
/// @dev Get the fillable taker amount of an order, taking into account
/// order state, maker fees, and maker balances.
function getOrderFillableTakerAmount(
IExchange.Order memory order,
bytes memory signature,
function getLimitOrderFillableTakerAmount(
IExchange.LimitOrder memory order,
IExchange.Signature memory signature,
IExchange exchange
)
virtual
@@ -220,88 +212,28 @@ contract NativeOrderSampler {
view
returns (uint256 fillableTakerAmount)
{
if (signature.length == 0 ||
order.makerAssetAmount == 0 ||
order.takerAssetAmount == 0)
if (signature.signatureType == IExchange.SignatureType.ILLEGAL ||
signature.signatureType == IExchange.SignatureType.INVALID ||
order.makerAmount == 0 ||
order.takerAmount == 0)
{
return 0;
}
IExchange.OrderInfo memory orderInfo = exchange.getOrderInfo(order);
if (orderInfo.orderStatus != IExchange.OrderStatus.FILLABLE) {
return 0;
}
if (!exchange.isValidHashSignature(orderInfo.orderHash, order.makerAddress, signature)) {
return 0;
}
address spender = exchange.getAssetProxy(ERC20_ASSET_PROXY_ID);
IERC20TokenV06 makerToken = _getTokenFromERC20AssetData(order.makerAssetData);
if (makerToken == IERC20TokenV06(0)) {
return 0;
}
IERC20TokenV06 makerFeeToken = order.makerFee > 0
? _getTokenFromERC20AssetData(order.makerFeeAssetData)
: IERC20TokenV06(0);
uint256 remainingTakerAmount = order.takerAssetAmount
.safeSub(orderInfo.orderTakerAssetFilledAmount);
fillableTakerAmount = remainingTakerAmount;
// The total fillable maker amount is the remaining fillable maker amount
// PLUS maker fees, if maker fees are denominated in the maker token.
uint256 totalFillableMakerAmount = LibMathV06.safeGetPartialAmountFloor(
remainingTakerAmount,
order.takerAssetAmount,
makerFeeToken == makerToken
? order.makerAssetAmount.safeAdd(order.makerFee)
: order.makerAssetAmount
);
// The spendable amount of maker tokens (by the maker) is the lesser of
// the maker's balance and the allowance they've granted to the ERC20Proxy.
uint256 spendableMakerAmount = LibSafeMathV06.min256(
makerToken.balanceOf(order.makerAddress),
makerToken.allowance(order.makerAddress, spender)
);
// Scale the fillable taker amount by the ratio of the maker's
// spendable maker amount over the total fillable maker amount.
if (spendableMakerAmount < totalFillableMakerAmount) {
fillableTakerAmount = LibMathV06.getPartialAmountCeil(
spendableMakerAmount,
totalFillableMakerAmount,
remainingTakerAmount
);
}
// If the maker fee is denominated in another token, constrain
// the fillable taker amount by how much the maker can pay of that token.
if (makerFeeToken != makerToken && makerFeeToken != IERC20TokenV06(0)) {
uint256 spendableExtraMakerFeeAmount = LibSafeMathV06.min256(
makerFeeToken.balanceOf(order.makerAddress),
makerFeeToken.allowance(order.makerAddress, spender)
);
if (spendableExtraMakerFeeAmount < order.makerFee) {
fillableTakerAmount = LibSafeMathV06.min256(
fillableTakerAmount,
LibMathV06.getPartialAmountCeil(
spendableExtraMakerFeeAmount,
order.makerFee,
remainingTakerAmount
)
);
}
}
}
(
IExchange.OrderInfo memory orderInfo,
uint128 remainingFillableTakerAmount,
bool isSignatureValid
) = exchange.getLimitOrderRelevantState(order, signature);
function _getTokenFromERC20AssetData(bytes memory assetData)
private
pure
returns (IERC20TokenV06 token)
{
if (assetData.length == 0) {
return IERC20TokenV06(address(0));
if (
orderInfo.status != IExchange.OrderStatus.FILLABLE ||
!isSignatureValid ||
order.makerToken == IERC20TokenV06(0)
) {
return 0;
}
if (assetData.length != 36 ||
assetData.readBytes4(0) != ERC20_ASSET_PROXY_ID)
{
return IERC20TokenV06(address(0));
}
return IERC20TokenV06(assetData.readAddress(16));
fillableTakerAmount = uint256(remainingFillableTakerAmount);
}
}

View File

@@ -31,11 +31,13 @@ contract UniswapV2Sampler is
uint256 constant private UNISWAPV2_CALL_GAS = 150e3; // 150k
/// @dev Sample sell quotes from UniswapV2.
/// @param router Router to look up tokens and amounts
/// @param path Token route. Should be takerToken -> makerToken
/// @param takerTokenAmounts Taker token sell amount for each sample.
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromUniswapV2(
address router,
address[] memory path,
uint256[] memory takerTokenAmounts
)
@@ -47,7 +49,7 @@ contract UniswapV2Sampler is
makerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
try
IUniswapV2Router01(_getUniswapV2Router01Address()).getAmountsOut
IUniswapV2Router01(router).getAmountsOut
{gas: UNISWAPV2_CALL_GAS}
(takerTokenAmounts[i], path)
returns (uint256[] memory amounts)
@@ -61,11 +63,13 @@ contract UniswapV2Sampler is
}
/// @dev Sample buy quotes from UniswapV2.
/// @param router Router to look up tokens and amounts
/// @param path Token route. Should be takerToken -> makerToken.
/// @param makerTokenAmounts Maker token buy amount for each sample.
/// @return takerTokenAmounts Taker amounts sold at each maker token
/// amount.
function sampleBuysFromUniswapV2(
address router,
address[] memory path,
uint256[] memory makerTokenAmounts
)
@@ -77,7 +81,7 @@ contract UniswapV2Sampler is
takerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
try
IUniswapV2Router01(_getUniswapV2Router01Address()).getAmountsIn
IUniswapV2Router01(router).getAmountsIn
{gas: UNISWAPV2_CALL_GAS}
(makerTokenAmounts[i], path)
returns (uint256[] memory amounts)

View File

@@ -0,0 +1,80 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
contract UtilitySampler {
using LibERC20TokenV06 for IERC20TokenV06;
IERC20TokenV06 private immutable UTILITY_ETH_ADDRESS = IERC20TokenV06(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function getTokenDecimals(IERC20TokenV06[] memory tokens)
public
view
returns (uint256[] memory decimals)
{
decimals = new uint256[](tokens.length);
for (uint256 i = 0; i != tokens.length; i++) {
decimals[i] = tokens[i] == UTILITY_ETH_ADDRESS
? 18
: tokens[i].compatDecimals();
}
}
function getBalanceOf(IERC20TokenV06[] memory tokens, address account)
public
view
returns (uint256[] memory balances)
{
balances = new uint256[](tokens.length);
for (uint256 i = 0; i != tokens.length; i++) {
balances[i] = tokens[i] == UTILITY_ETH_ADDRESS
? account.balance
: tokens[i].compatBalanceOf(account);
}
}
function getAllowanceOf(IERC20TokenV06[] memory tokens, address account, address spender)
public
view
returns (uint256[] memory allowances)
{
allowances = new uint256[](tokens.length);
for (uint256 i = 0; i != tokens.length; i++) {
allowances[i] = tokens[i] == UTILITY_ETH_ADDRESS
? 0
: tokens[i].compatAllowance(account, spender);
}
}
function isContract(address account)
public
view
returns (bool)
{
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
}

View File

@@ -480,9 +480,9 @@ contract TestERC20BridgeSampler is
}
// Overridden to return deterministic states.
function getOrderFillableTakerAmount(
IExchange.Order memory order,
bytes memory,
function getLimitOrderFillableTakerAmount(
IExchange.LimitOrder memory order,
IExchange.Signature memory,
IExchange
)
override
@@ -490,7 +490,7 @@ contract TestERC20BridgeSampler is
view
returns (uint256 fillableTakerAmount)
{
return uint256(keccak256(abi.encode(order.salt))) % order.takerAssetAmount;
return uint256(keccak256(abi.encode(order.salt))) % order.takerAmount;
}
// Overriden to return deterministic decimals.

View File

@@ -20,6 +20,7 @@ pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "../src/NativeOrderSampler.sol";
import "../src/UtilitySampler.sol";
contract TestNativeOrderSamplerToken {
@@ -40,7 +41,8 @@ contract TestNativeOrderSamplerToken {
}
contract TestNativeOrderSampler is
NativeOrderSampler
NativeOrderSampler,
UtilitySampler
{
uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1;
bytes32 private constant VALID_SIGNATURE_HASH = keccak256(hex"01");
@@ -67,42 +69,67 @@ contract TestNativeOrderSampler is
token.setBalanceAndAllowance(owner, spender, balance, allowance);
}
// IExchange.getAssetProxy()
function getAssetProxy(bytes4 proxyId)
public
pure
returns (address)
{
return address(uint160(uint256(keccak256(abi.encode(proxyId)))));
}
// IExchange.getOrderInfo()
function getOrderInfo(IExchange.Order calldata order)
// IExchange.getLimitOrderRelevantState()
function getLimitOrderRelevantState(
IExchange.LimitOrder memory order,
IExchange.Signature calldata signature
)
external
pure
returns (IExchange.OrderInfo memory orderInfo)
view
returns (
IExchange.OrderInfo memory orderInfo,
uint128 actualFillableTakerTokenAmount,
bool isSignatureValid
)
{
// The order salt determines everything.
orderInfo.orderHash = keccak256(abi.encode(order.salt));
if (uint8(order.salt) == 0xFF) {
orderInfo.orderStatus = IExchange.OrderStatus.FULLY_FILLED;
orderInfo.status = IExchange.OrderStatus.FILLED;
} else {
orderInfo.orderStatus = IExchange.OrderStatus.FILLABLE;
orderInfo.status = IExchange.OrderStatus.FILLABLE;
}
isSignatureValid = signature.r == VALID_SIGNATURE_HASH;
// The expiration time is the filled taker asset amount.
orderInfo.orderTakerAssetFilledAmount = order.expirationTimeSeconds;
orderInfo.takerTokenFilledAmount = uint128(order.expiry);
// Calculate how much is fillable in maker terms given the filled taker amount
uint256 fillableMakerTokenAmount = LibMathV06.getPartialAmountFloor(
uint256(
order.takerAmount
- orderInfo.takerTokenFilledAmount
),
uint256(order.takerAmount),
uint256(order.makerAmount)
);
// Take the min of the balance/allowance and the fillable maker amount
fillableMakerTokenAmount = LibSafeMathV06.min256(
fillableMakerTokenAmount,
_getSpendableERC20BalanceOf(order.makerToken, order.maker)
);
// Convert to taker terms
actualFillableTakerTokenAmount = LibMathV06.getPartialAmountCeil(
fillableMakerTokenAmount,
uint256(order.makerAmount),
uint256(order.takerAmount)
).safeDowncastToUint128();
}
// IExchange.isValidSignature()
function isValidHashSignature(
bytes32,
address,
bytes calldata signature
function _getSpendableERC20BalanceOf(
IERC20TokenV06 token,
address owner
)
external
pure
returns (bool isValid)
internal
view
returns (uint256)
{
return keccak256(signature) == VALID_SIGNATURE_HASH;
return LibSafeMathV06.min256(
token.allowance(owner, address(this)),
token.balanceOf(owner)
);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/asset-swapper",
"version": "5.8.2",
"version": "6.0.0",
"engines": {
"node": ">=6.12"
},
@@ -38,7 +38,7 @@
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json",
"postpublish": {
"assets": []
}
@@ -59,12 +59,11 @@
"dependencies": {
"@0x/assert": "^3.0.21",
"@0x/base-contract": "^6.2.18",
"@0x/contract-addresses": "^5.9.0",
"@0x/contract-wrappers": "^13.12.2",
"@0x/contract-addresses": "^5.10.0",
"@0x/contract-wrappers": "^13.12.3",
"@0x/dev-utils": "^4.2.1",
"@0x/json-schemas": "^5.4.1",
"@0x/order-utils": "^10.4.15",
"@0x/orderbook": "0xProject/gitpkg-registry#0x-orderbook-v2.2.7-e10a81023",
"@0x/protocol-utils": "^1.2.0",
"@0x/quote-server": "^4.0.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
@@ -87,16 +86,16 @@
},
"devDependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-asset-proxy": "^3.7.5",
"@0x/contracts-erc20": "^3.3.2",
"@0x/contracts-exchange": "^3.2.24",
"@0x/contracts-exchange-libs": "^4.3.23",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-zero-ex": "^0.18.1",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/contracts-zero-ex": "^0.18.2",
"@0x/mesh-rpc-client": "^9.4.2",
"@0x/migrations": "^6.5.11",
"@0x/migrations": "^6.6.0",
"@0x/sol-compiler": "^4.5.2",
"@0x/subproviders": "^6.4.1",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,15 +1,13 @@
import { ChainId } from '@0x/contract-addresses';
import { SignatureType } from '@0x/protocol-utils';
import { BigNumber, logUtils } from '@0x/utils';
import {
ExchangeProxyContractOpts,
ExtensionContractType,
ForwarderExtensionContractOpts,
LogFunction,
OrderPrunerOpts,
OrderPrunerPermittedFeeTypes,
RfqtRequestOpts,
SwapQuoteExecutionOpts,
SwapQuoteGetOutputOpts,
SwapQuoteRequestOpts,
SwapQuoterOpts,
@@ -29,10 +27,7 @@ const ZERO_AMOUNT = new BigNumber(0);
const DEFAULT_ORDER_PRUNER_OPTS: OrderPrunerOpts = {
expiryBufferMs: 120000, // 2 minutes
permittedOrderFeeTypes: new Set<OrderPrunerPermittedFeeTypes>([
OrderPrunerPermittedFeeTypes.NoFees,
OrderPrunerPermittedFeeTypes.MakerDenominatedTakerFee,
]), // Default asset-swapper for CFL oriented fee types
permittedOrderFeeTypes: new Set<OrderPrunerPermittedFeeTypes>([OrderPrunerPermittedFeeTypes.NoFees]), // Default asset-swapper for CFL oriented fee types
};
// 6 seconds polling interval
@@ -55,16 +50,6 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
},
};
const DEFAULT_FORWARDER_EXTENSION_CONTRACT_OPTS: ForwarderExtensionContractOpts = {
feePercentage: 0,
feeRecipient: NULL_ADDRESS,
};
const DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS: SwapQuoteGetOutputOpts = {
useExtensionContract: ExtensionContractType.Forwarder,
extensionContractOpts: DEFAULT_FORWARDER_EXTENSION_CONTRACT_OPTS,
};
const DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS: ExchangeProxyContractOpts = {
isFromETH: false,
isToETH: false,
@@ -78,10 +63,7 @@ const DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS: ExchangeProxyContractOpts
shouldSellEntireBalance: false,
};
const DEFAULT_FORWARDER_SWAP_QUOTE_EXECUTE_OPTS: SwapQuoteExecutionOpts = DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS;
const DEFAULT_EXCHANGE_PROXY_SWAP_QUOTE_GET_OPTS: SwapQuoteGetOutputOpts = {
useExtensionContract: ExtensionContractType.ExchangeProxy,
extensionContractOpts: DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS,
};
@@ -91,10 +73,6 @@ const DEFAULT_SWAP_QUOTE_REQUEST_OPTS: SwapQuoteRequestOpts = {
const DEFAULT_RFQT_REQUEST_OPTS: Partial<RfqtRequestOpts> = {
makerEndpointMaxResponseTimeMs: 1000,
priceAwareRFQFlag: {
isFirmPriceAwareEnabled: false,
isIndicativePriceAwareEnabled: false,
},
};
export const DEFAULT_INFO_LOGGER: LogFunction = (obj, msg) =>
@@ -102,14 +80,8 @@ export const DEFAULT_INFO_LOGGER: LogFunction = (obj, msg) =>
export const DEFAULT_WARNING_LOGGER: LogFunction = (obj, msg) =>
logUtils.warn(`${msg ? `${msg}: ` : ''}${JSON.stringify(obj)}`);
// This feature flag allows us to merge the price-aware RFQ pricing
// project while still controlling when to activate the feature. We plan to do some
// data analysis work and address some of the issues with maker fillable amounts
// in later milestones. Once the feature is fully rolled out and is providing value
// and we have assessed that there is no user impact, we will proceed in cleaning up
// the feature flag. When that time comes, follow this PR to "undo" the feature flag:
// https://github.com/0xProject/0x-monorepo/pull/2735
export const IS_PRICE_AWARE_RFQ_ENABLED: boolean = false;
const EMPTY_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
export const INVALID_SIGNATURE = { signatureType: SignatureType.Invalid, v: 1, r: EMPTY_BYTES32, s: EMPTY_BYTES32 };
export {
BRIDGE_ADDRESSES_BY_CHAIN,
@@ -131,8 +103,6 @@ export const constants = {
ONE_MINUTE_MS,
DEFAULT_SWAP_QUOTER_OPTS,
DEFAULT_INTERMEDIATE_TOKENS,
DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS,
DEFAULT_FORWARDER_SWAP_QUOTE_EXECUTE_OPTS,
DEFAULT_SWAP_QUOTE_REQUEST_OPTS,
DEFAULT_EXCHANGE_PROXY_SWAP_QUOTE_GET_OPTS,
DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS,
@@ -144,4 +114,5 @@ export const constants = {
BRIDGE_ASSET_DATA_PREFIX: '0xdc1600f3',
DEFAULT_INFO_LOGGER,
DEFAULT_WARNING_LOGGER,
EMPTY_BYTES32,
};

View File

@@ -5,30 +5,18 @@ export {
SendTransactionOpts,
} from '@0x/base-contract';
export { ContractAddresses } from '@0x/contract-addresses';
export { WSOpts } from '@0x/mesh-rpc-client';
export {
AcceptedRejectedOrders,
AddedRemovedOrders,
BaseOrderProvider,
MeshOrderProviderOpts,
Orderbook,
OrderSet,
OrderStore,
RejectedOrder,
SRAPollingOrderProviderOpts,
SRAWebsocketOrderProviderOpts,
} from '@0x/orderbook';
export { V3RFQFirmQuote, V3RFQIndicativeQuote, TakerRequestQueryParams } from '@0x/quote-server';
export {
APIOrder,
Asset,
AssetPairsItem,
DecodedLogEvent,
EventCallback,
IndexedFilterValues,
SignedOrder,
} from '@0x/types';
export { V4RFQFirmQuote, V4RFQIndicativeQuote, V4SignedRfqOrder, TakerRequestQueryParams } from '@0x/quote-server';
export { Asset, AssetPairsItem, DecodedLogEvent, EventCallback, IndexedFilterValues } from '@0x/types';
export { BigNumber } from '@0x/utils';
export {
RfqOrderFields,
LimitOrderFields,
FillQuoteTransformerOrderType,
RfqOrder,
LimitOrder,
Signature,
SignatureType,
} from '@0x/protocol-utils';
export { AxiosInstance } from 'axios';
export {
AbiDefinition,
@@ -84,29 +72,26 @@ export {
export { artifacts } from './artifacts';
export { InsufficientAssetLiquidityError } from './errors';
export { SwapQuoteConsumer } from './quote_consumers/swap_quote_consumer';
export { getSwapMinBuyAmount, getQuoteInfoMinBuyAmount } from './quote_consumers/utils';
export { SwapQuoter } from './swap_quoter';
export { SwapQuoter, Orderbook } from './swap_quoter';
export {
AffiliateFee,
AssetSwapperContractAddresses,
CalldataInfo,
ExchangeProxyContractOpts,
ExchangeProxyRefundReceiver,
ExtensionContractType,
ForwarderExtensionContractOpts,
GetExtensionContractTypeOpts,
LiquidityForTakerMakerAssetDataPair,
LogFunction,
MarketBuySwapQuote,
MarketOperation,
MarketSellSwapQuote,
MockedRfqtFirmQuoteResponse,
MockedRfqtQuoteResponse,
OrderPrunerPermittedFeeTypes,
RfqtMakerAssetOfferings,
RfqtFirmQuoteValidator,
RfqtRequestOpts,
SamplerOverrides,
SignedOrderWithFillableAmounts,
SignedNativeOrder,
SignedOrder,
SwapQuote,
SwapQuoteConsumerBase,
SwapQuoteConsumerError,
@@ -154,11 +139,12 @@ export {
MooniswapFillData,
MultiHopFillData,
NativeCollapsedFill,
NativeRfqOrderFillData,
NativeLimitOrderFillData,
NativeFillData,
OptimizedMarketOrder,
SnowSwapFillData,
SnowSwapInfo,
SourceInfo,
SourceQuoteOperation,
SushiSwapFillData,
SwerveFillData,
@@ -168,16 +154,17 @@ export {
} from './utils/market_operation_utils/types';
export { ProtocolFeeUtils } from './utils/protocol_fee_utils';
export {
BridgeReportSource,
MultiHopReportSource,
NativeOrderbookReportSource,
NativeRFQTReportSource,
BridgeQuoteReportEntry,
MultiHopQuoteReportEntry,
NativeLimitOrderQuoteReportEntry,
NativeRfqOrderQuoteReportEntry,
QuoteReport,
QuoteReportSource,
QuoteReportEntry,
} from './utils/quote_report_generator';
export { QuoteRequestor } from './utils/quote_requestor';
export { rfqtMocker } from './utils/rfqt_mocker';
export { ERC20BridgeSamplerContract, BalanceCheckerContract } from './wrappers';
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
export type Native = ERC20BridgeSource.Native;
export type MultiHop = ERC20BridgeSource.MultiHop;
export { rfqtMocker, RfqtQuoteEndpoint } from './utils/rfqt_mocker';

View File

@@ -6,9 +6,11 @@ import {
encodePayTakerTransformerData,
encodeWethTransformerData,
ETH_TOKEN_ADDRESS,
FillQuoteTransformerData,
FillQuoteTransformerOrderType,
FillQuoteTransformerSide,
findTransformerNonce,
} from '@0x/order-utils';
} from '@0x/protocol-utils';
import { BigNumber, providerUtils } from '@0x/utils';
import { SupportedProvider, ZeroExProvider } from '@0x/web3-wrapper';
import * as _ from 'lodash';
@@ -27,10 +29,20 @@ import {
SwapQuoteGetOutputOpts,
} from '../types';
import { assert } from '../utils/assert';
import { ERC20BridgeSource, UniswapV2FillData } from '../utils/market_operation_utils/types';
import { getTokenFromAssetData } from '../utils/utils';
import { getSwapMinBuyAmount } from './utils';
import {
createBridgeDataForBridgeOrder,
getERC20BridgeSourceToBridgeSource,
} from '../utils/market_operation_utils/orders';
import {
ERC20BridgeSource,
LiquidityProviderFillData,
NativeLimitOrderFillData,
NativeRfqOrderFillData,
OptimizedMarketBridgeOrder,
OptimizedMarketOrder,
OptimizedMarketOrderBase,
UniswapV2FillData,
} from '../utils/market_operation_utils/types';
// tslint:disable-next-line:custom-no-magic-numbers
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
@@ -84,7 +96,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
quote: MarketBuySwapQuote | MarketSellSwapQuote,
opts: Partial<SwapQuoteGetOutputOpts> = {},
): Promise<CalldataInfo> {
assert.isValidSwapQuote('quote', quote);
const optsWithDefaults: ExchangeProxyContractOpts = {
...constants.DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS,
...opts.extensionContractOpts,
@@ -92,11 +103,14 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
// tslint:disable-next-line:no-object-literal-type-assertion
const { refundReceiver, affiliateFee, isFromETH, isToETH, shouldSellEntireBalance } = optsWithDefaults;
const sellToken = getTokenFromAssetData(quote.takerAssetData);
const buyToken = getTokenFromAssetData(quote.makerAssetData);
const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount;
let minBuyAmount = getSwapMinBuyAmount(quote);
const sellToken = quote.takerToken;
const buyToken = quote.makerToken;
// Take the bounds from the worst case
const sellAmount = quote.worstCaseQuoteInfo.totalTakerAmount;
let minBuyAmount = quote.worstCaseQuoteInfo.makerAmount;
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
if (isFromETH) {
ethAmount = ethAmount.plus(sellAmount);
}
@@ -106,8 +120,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
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;
const source = quote.orders[0].source;
const fillData = (quote.orders[0] as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData;
return {
calldataHexString: this._exchangeProxy
.sellToUniswap(
@@ -132,7 +146,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}
if (isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.LiquidityProvider])) {
const target = quote.orders[0].makerAddress;
const fillData = (quote.orders[0] as OptimizedMarketBridgeOrder<LiquidityProviderFillData>).fillData;
const target = fillData.poolAddress;
return {
calldataHexString: this._exchangeProxy
.sellToLiquidityProvider(
@@ -164,52 +179,46 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
});
}
const intermediateToken = quote.isTwoHop ? getTokenFromAssetData(quote.orders[0].makerAssetData) : NULL_ADDRESS;
// If it's two hop we have an intermediate token this is needed to encode the individual FQT
// and we also want to ensure no dust amount is left in the flash wallet
const intermediateToken = quote.isTwoHop ? quote.orders[0].makerToken : NULL_ADDRESS;
// This transformer will fill the quote.
if (quote.isTwoHop) {
const [firstHopOrder, secondHopOrder] = quote.orders;
transforms.push({
deploymentNonce: this.transformerNonces.fillQuoteTransformer,
data: encodeFillQuoteTransformerData({
side: FillQuoteTransformerSide.Sell,
sellToken,
buyToken: intermediateToken,
side: FillQuoteTransformerSide.Sell,
...getFQTTransformerDataFromOptimizedOrders([firstHopOrder]),
refundReceiver: refundReceiver || NULL_ADDRESS,
fillAmount: shouldSellEntireBalance ? MAX_UINT256 : firstHopOrder.takerAssetAmount,
maxOrderFillAmounts: [],
rfqtTakerAddress: NULL_ADDRESS,
orders: [firstHopOrder],
signatures: [firstHopOrder.signature],
fillAmount: shouldSellEntireBalance ? MAX_UINT256 : firstHopOrder.takerAmount,
}),
});
transforms.push({
deploymentNonce: this.transformerNonces.fillQuoteTransformer,
data: encodeFillQuoteTransformerData({
side: FillQuoteTransformerSide.Sell,
buyToken,
sellToken: intermediateToken,
...getFQTTransformerDataFromOptimizedOrders([secondHopOrder]),
refundReceiver: refundReceiver || NULL_ADDRESS,
side: FillQuoteTransformerSide.Sell,
fillAmount: MAX_UINT256,
maxOrderFillAmounts: [],
rfqtTakerAddress: NULL_ADDRESS,
orders: [secondHopOrder],
signatures: [secondHopOrder.signature],
}),
});
} else {
const fillAmount = isBuyQuote(quote) ? quote.makerAssetFillAmount : quote.takerAssetFillAmount;
const fillAmount = isBuyQuote(quote) ? quote.makerTokenFillAmount : quote.takerTokenFillAmount;
transforms.push({
deploymentNonce: this.transformerNonces.fillQuoteTransformer,
data: encodeFillQuoteTransformerData({
side: isBuyQuote(quote) ? FillQuoteTransformerSide.Buy : FillQuoteTransformerSide.Sell,
sellToken,
buyToken,
...getFQTTransformerDataFromOptimizedOrders(quote.orders),
refundReceiver: refundReceiver || NULL_ADDRESS,
side: isBuyQuote(quote) ? FillQuoteTransformerSide.Buy : FillQuoteTransformerSide.Sell,
fillAmount: !isBuyQuote(quote) && shouldSellEntireBalance ? MAX_UINT256 : fillAmount,
maxOrderFillAmounts: [],
rfqtTakerAddress: NULL_ADDRESS,
orders: quote.orders,
signatures: quote.orders.map(o => o.signature),
}),
});
}
@@ -282,10 +291,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}
}
function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote {
return quote.type === MarketOperation.Buy;
}
function isDirectSwapCompatible(
quote: SwapQuote,
opts: ExchangeProxyContractOpts,
@@ -304,12 +309,7 @@ function isDirectSwapCompatible(
return false;
}
const order = quote.orders[0];
// With a single underlying fill/source.
if (order.fills.length !== 1) {
return false;
}
const fill = order.fills[0];
if (!directSources.includes(fill.source)) {
if (!directSources.includes(order.source)) {
return false;
}
// VIP does not support selling the entire balance
@@ -318,3 +318,58 @@ function isDirectSwapCompatible(
}
return true;
}
function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote {
return quote.type === MarketOperation.Buy;
}
function isOptimizedBridgeOrder(x: OptimizedMarketOrder): x is OptimizedMarketBridgeOrder {
return x.type === FillQuoteTransformerOrderType.Bridge;
}
function isOptimizedLimitOrder(x: OptimizedMarketOrder): x is OptimizedMarketOrderBase<NativeLimitOrderFillData> {
return x.type === FillQuoteTransformerOrderType.Limit;
}
function isOptimizedRfqOrder(x: OptimizedMarketOrder): x is OptimizedMarketOrderBase<NativeRfqOrderFillData> {
return x.type === FillQuoteTransformerOrderType.Rfq;
}
function getFQTTransformerDataFromOptimizedOrders(
orders: OptimizedMarketOrder[],
): Pick<FillQuoteTransformerData, 'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'fillSequence'> {
const fqtData: Pick<FillQuoteTransformerData, 'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'fillSequence'> = {
bridgeOrders: [],
limitOrders: [],
rfqOrders: [],
fillSequence: [],
};
for (const order of orders) {
if (isOptimizedBridgeOrder(order)) {
fqtData.bridgeOrders.push({
bridgeData: createBridgeDataForBridgeOrder(order),
makerTokenAmount: order.makerAmount,
takerTokenAmount: order.takerAmount,
source: getERC20BridgeSourceToBridgeSource(order.source),
});
} else if (isOptimizedLimitOrder(order)) {
fqtData.limitOrders.push({
order: order.fillData.order,
signature: order.fillData.signature,
maxTakerTokenFillAmount: order.takerAmount,
});
} else if (isOptimizedRfqOrder(order)) {
fqtData.rfqOrders.push({
order: order.fillData.order,
signature: order.fillData.signature,
maxTakerTokenFillAmount: order.takerAmount,
});
} else {
// Should never happen
throw new Error('Unknown Order type');
}
fqtData.fillSequence.push(order.type);
}
return fqtData;
}

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