Compare commits

..

27 Commits

Author SHA1 Message Date
Github Actions
61c5e7b948 Publish
- @0x/contracts-integrations@2.7.28
 - @0x/asset-swapper@6.2.0
2021-03-02 00:44:13 +00:00
Github Actions
5fd78ef32f Updated CHANGELOGS & MD docs 2021-03-02 00:44:06 +00:00
Lawrence Forman
14ff9b827c @0x/asset-swapper: Drop Y and BUSD curve pools (#161) 2021-03-02 07:56:43 +10:00
Lawrence Forman
598dc2cd71 docs: update allowances blurb (#160) 2021-02-25 17:11:44 -05:00
Github Actions
08e1c5109f Publish
- @0x/contracts-asset-proxy@3.7.7
 - @0x/contracts-broker@1.1.25
 - @0x/contracts-coordinator@3.1.26
 - @0x/contracts-dev-utils@1.3.24
 - @0x/contracts-erc1155@2.1.25
 - @0x/contracts-erc20@3.3.4
 - @0x/contracts-erc721@3.1.25
 - @0x/contracts-exchange-forwarder@4.2.26
 - @0x/contracts-exchange-libs@4.3.25
 - @0x/contracts-exchange@3.2.26
 - @0x/contracts-extensions@6.2.20
 - @0x/contracts-integrations@2.7.27
 - @0x/contracts-multisig@4.1.26
 - @0x/contracts-staking@2.0.33
 - @0x/contracts-test-utils@5.3.22
 - @0x/contracts-treasury@1.0.2
 - @0x/contracts-utils@4.7.4
 - @0x/contracts-zero-ex@0.19.0
 - @0x/asset-swapper@6.1.0
 - @0x/contract-addresses@5.11.0
 - @0x/contract-artifacts@3.12.0
 - @0x/contract-wrappers-test@12.2.37
 - @0x/contract-wrappers@13.13.0
 - @0x/migrations@7.0.0
 - @0x/order-utils@10.4.17
 - @0x/protocol-utils@1.3.0
2021-02-24 04:42:41 +00:00
Github Actions
6f7a843742 Updated CHANGELOGS & MD docs 2021-02-24 04:42:32 +00:00
Jacob Evans
c9c9615bb5 Fix contract merge conflict 2021-02-24 14:08:54 +10:00
Romain Butteaud
f98609686d feat: opt-in positive slippage fee for integrators (#101)
* feat: Positive Slippage Fee

* fix: rename ethToTakerAssetRate to takerAssetPriceForOneEth

* fix: rename takerAssetPriceForOneEth to takerAssetsPerEth

* fix: export AffiliateFeeType

* rebased off development

* Add a gasOverhead for non-deterministic operations

* CHANGELOGs

* rename outputTokens to outputAmount

* Confirm transformer addresses on Mainnet and Ropsten

* fix import

Co-authored-by: Jacob Evans <jacob@dekz.net>
2021-02-24 12:51:58 +10:00
Jacob Evans
5b8bbc34e8 fix: FQT in migrations (#157) 2021-02-24 12:36:58 +10:00
Jacob Evans
49cb00a9ab feat: DODO V2, Linkswap (#152)
* feat: DODO V2

* Fix typo

* feat: Linkswap (#153)

* fix: intermediate hops WBTC (#154)

* feat: Linkswap

* fix: Re-add WBTC in default hop tokens

* Update review changes

* FQT deploy + no gas limit ETH refund (#155)

* `@0x/contracts-zero-ex`: refund ETH with no gas limit in FQT
`@0x/contract-addresses`: Deploy FQT

* Update packages/contract-addresses/CHANGELOG.json

Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>

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

Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>
2021-02-24 12:19:26 +10:00
Alex Kroeger
74b240fb88 add exchange proxy overhead penalty to comparison price (#156)
* add exchange proxy overhead penalty to comparison price

* prettier
2021-02-23 17:32:15 -08:00
Alex Kroeger
514f9d2621 feat/alt RFQ MM implementation (#139)
* baseline adapter code [WIP]

* fixed adapter logic, quote_requester instantiation

* modified quote-requestor test to include alt implementation

* type changes, fixes to quote requestor test

* small fixes

* working tests, made alt utils more readable

* lint errors

* added alt indicative quote tests, minor fixes

* export alt MM market offering types

* altered alt market offering to have id instead of symbols

* addressed minor comments

* updated changelog

* got rid of unnecessary, large if-block, fixed the buy-sell assignment to be from the MM's perspective

* extra logging for debugging

* fixed existingOrder size

* get rid of only flag on test, get rid of extra logging

* prettier
2021-02-22 16:07:30 -08:00
Jacob Evans
fa78d1092a feat: asset-swapper Fake Taker contract (#151) 2021-02-22 08:32:53 +10:00
Lawrence Forman
297342092b @0x/asset-swapper: special case BNB in uni v1 sampler (#147)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-02-19 16:56:16 +10:00
Jacob Evans
076f263a86 feat: Validate v4 limit orders (#148)
re-renable tests
2021-02-19 16:42:10 +10:00
Jacob Evans
0c56207abc fix: Protocol fee in fee schedule (#146)
* fix: Protocol fee in fee schedule

* CHANGELOG

* hack imports
2021-02-18 14:12:11 +10:00
Lawrence Forman
23953d8a5a Update artifacts and wrappers (#145)
* `@0x/contract-artifacts`: Update artifacts.
`@0x/contract-wrappers`: Regenerate wrappers

* fix doc gen

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-02-17 14:34:43 -05:00
Jacob Evans
c6919eb25a feat: Mirror Protocol tokens (#142)
* feat: Mirror Protocol tokens

* added .tap to builder
2021-02-17 10:14:38 +10:00
Lawrence Forman
d509604b52 @0x/contracts-zero-ex: Export CurveLiquidityProviderContract (#144)
`@0x/asset-swapper`: Add deployed `CurveLiquidityProvider` addresses

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-02-16 16:17:08 -05:00
Lawrence Forman
a74a3450eb @0x/contracts-zero-ex: Add CurveLiquidityProvider and misc refactors (#127)
* `@0x/contracts-zero-ex`: Add `CurveLiquidityProvider` and misc refactors

* `@0x/asset-swapper`: Fix compiler error on `ILiquidityProvider` call
`@0x/protocol-utils`: Add VIP utils.

* `@0x/contracts-zero-ex`: Rebase and fix comiler warnings

* `@0x/asset-swapper`: Clean up curve VIP integration

* `@0x/protocol-utils`: Update changelog

* `@0x/protocol-utils`: tsdoc new functions

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-02-11 19:13:17 -05:00
Jacob Evans
72c5399b9d fix: Second hop source is missing (#138)
* fix: Second hop source is missing

* CHANGELOGs
2021-02-11 00:13:58 +10:00
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
243 changed files with 9458 additions and 10337 deletions

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.7.7 - _February 24, 2021_
* Dependencies updated
## 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.7",
"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.13.0",
"@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.22",
"@0x/contracts-utils": "^4.7.4",
"@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.25",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-erc721": "^3.1.25",
"@0x/contracts-exchange-libs": "^4.3.25",
"@0x/order-utils": "^10.4.17",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.1.25 - _February 24, 2021_
* Dependencies updated
## 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.25",
"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.7",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-erc721": "^3.1.25",
"@0x/contracts-exchange": "^3.2.26",
"@0x/contracts-exchange-libs": "^4.3.25",
"@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.22",
"@0x/contracts-utils": "^4.7.4",
"@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.17",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",
"ethereum-types": "^3.4.0"

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.26 - _February 24, 2021_
* Dependencies updated
## 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.26",
"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.7",
"@0x/contracts-dev-utils": "^1.3.24",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-gen": "^2.0.30",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.17",
"@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.11.0",
"@0x/contracts-exchange": "^3.2.26",
"@0x/contracts-test-utils": "^5.3.22",
"@0x/contracts-utils": "^4.7.4",
"@0x/json-schemas": "^5.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.3.24 - _February 24, 2021_
* Dependencies updated
## 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.24",
"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.7",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.22",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.1.25 - _February 24, 2021_
* Dependencies updated
## 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.25",
"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.4",
"@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.22",
"@0x/utils": "^6.2.0",
"@0x/web3-wrapper": "^7.4.1",
"lodash": "^4.17.11"

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.3.4 - _February 24, 2021_
* Dependencies updated
## 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.4",
"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.22",
"@0x/contracts-utils": "^4.7.4",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.25 - _February 24, 2021_
* Dependencies updated
## 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.25",
"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.22",
"@0x/contracts-utils": "^4.7.4",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.2.26 - _February 24, 2021_
* Dependencies updated
## 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.26",
"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.7",
"@0x/contracts-dev-utils": "^1.3.24",
"@0x/contracts-erc1155": "^2.1.25",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-erc721": "^3.1.25",
"@0x/contracts-exchange": "^3.2.26",
"@0x/contracts-exchange-libs": "^4.3.25",
"@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.22",
"@0x/contracts-utils": "^4.7.4",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.17",
"@0x/sol-compiler": "^4.5.2",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.3.25 - _February 24, 2021_
* Dependencies updated
## 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.25",
"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.22",
"@0x/contracts-utils": "^4.7.4",
"@0x/order-utils": "^10.4.17",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.26 - _February 24, 2021_
* Dependencies updated
## 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.26",
"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.7",
"@0x/contracts-exchange-libs": "^4.3.25",
"@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.26",
"@0x/contracts-staking": "^2.0.33",
"@0x/contracts-test-utils": "^5.3.22",
"@0x/contracts-utils": "^4.7.4",
"@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.24",
"@0x/contracts-erc1155": "^2.1.25",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-erc721": "^3.1.25",
"@0x/order-utils": "^10.4.17",
"@0x/utils": "^6.2.0",
"lodash": "^4.17.11"
},

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v6.2.20 - _February 24, 2021_
* Dependencies updated
## 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.20",
"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.7",
"@0x/contracts-dev-utils": "^1.3.24",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-erc721": "^3.1.25",
"@0x/contracts-exchange": "^3.2.26",
"@0x/contracts-exchange-libs": "^4.3.25",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-utils": "^4.7.4",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.17",
"@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.22",
"@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.28",
"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.11.0",
"@0x/contract-wrappers": "^13.13.0",
"@0x/contracts-broker": "^1.1.25",
"@0x/contracts-coordinator": "^3.1.26",
"@0x/contracts-dev-utils": "^1.3.24",
"@0x/contracts-exchange-forwarder": "^4.2.26",
"@0x/contracts-exchange-libs": "^4.3.25",
"@0x/contracts-extensions": "^6.2.20",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-utils": "^4.7.4",
"@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": "^7.0.0",
"@0x/order-utils": "^10.4.17",
"@0x/protocol-utils": "^1.3.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.2.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.7",
"@0x/contracts-erc1155": "^2.1.25",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-erc721": "^3.1.25",
"@0x/contracts-exchange": "^3.2.26",
"@0x/contracts-multisig": "^4.1.26",
"@0x/contracts-staking": "^2.0.33",
"@0x/contracts-test-utils": "^5.3.22",
"@0x/contracts-zero-ex": "^0.19.0",
"@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,22 @@
[
{
"timestamp": 1614141718,
"version": "4.1.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "4.1.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "4.1.24",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.1.26 - _February 24, 2021_
* Dependencies updated
## 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.26",
"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.7",
"@0x/contracts-erc20": "^3.3.4",
"@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.22",
"@0x/contracts-utils": "^4.7.4",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/tslint-config": "^4.1.3",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.33 - _February 24, 2021_
* Dependencies updated
## 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.33",
"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.7",
"@0x/contracts-dev-utils": "^1.3.24",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-exchange-libs": "^4.3.25",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.2",
"@0x/contracts-utils": "^4.7.4",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.17",
"@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.22",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",
"ethereum-types": "^3.4.0",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.3.22 - _February 24, 2021_
* Dependencies updated
## 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.22",
"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.11.0",
"@0x/dev-utils": "^4.2.1",
"@0x/json-schemas": "^5.4.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.17",
"@0x/sol-coverage": "^4.0.29",
"@0x/sol-profiler": "^4.1.19",
"@0x/sol-trace": "^3.0.29",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.2 - _February 24, 2021_
* Dependencies updated
## 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.2",
"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.11.0",
"@0x/contracts-asset-proxy": "^3.7.7",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-staking": "^2.0.29",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-staking": "^2.0.33",
"@0x/contracts-test-utils": "^5.3.22",
"@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.3.0",
"@0x/subproviders": "^6.2.3",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.7.4 - _February 24, 2021_
* Dependencies updated
## 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.4",
"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.22",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.17",
"@0x/sol-compiler": "^4.5.2",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",

View File

@@ -1,4 +1,44 @@
[
{
"version": "0.19.0",
"changes": [
{
"note": "Add `CurveLiquidityProvider` and misc refactors",
"pr": 127
},
{
"note": "Export `CurveLiquidityProviderContract`",
"pr": 144
},
{
"note": "Add `DodoV2`",
"pr": 152
},
{
"note": "Add `Linkswap`",
"pr": 153
},
{
"note": "refund ETH with no gas limit in FQT",
"pr": 155
},
{
"note": "Added an opt-in `PositiveSlippageAffiliateFee`",
"pr": 101
}
],
"timestamp": 1614141718
},
{
"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,19 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v0.19.0 - _February 24, 2021_
* Add `CurveLiquidityProvider` and misc refactors (#127)
* Export `CurveLiquidityProviderContract` (#144)
* Add `DodoV2` (#152)
* Add `Linkswap` (#153)
* refund ETH with no gas limit in FQT (#155)
* Added an opt-in `PositiveSlippageAffiliateFee` (#101)
## 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

@@ -20,6 +20,9 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../vendor/ILiquidityProvider.sol";
interface ILiquidityProviderSandbox {
@@ -32,9 +35,9 @@ interface ILiquidityProviderSandbox {
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForToken(
address provider,
address inputToken,
address outputToken,
ILiquidityProvider provider,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -49,8 +52,8 @@ interface ILiquidityProviderSandbox {
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellEthForToken(
address provider,
address outputToken,
ILiquidityProvider provider,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -65,8 +68,8 @@ interface ILiquidityProviderSandbox {
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForEth(
address provider,
address inputToken,
ILiquidityProvider provider,
IERC20TokenV06 inputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData

View File

@@ -17,6 +17,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibOwnableRichErrorsV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../vendor/ILiquidityProvider.sol";
import "../vendor/v3/IERC20Bridge.sol";
import "./ILiquidityProviderSandbox.sol";
@@ -58,9 +59,9 @@ contract LiquidityProviderSandbox is
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForToken(
address provider,
address inputToken,
address outputToken,
ILiquidityProvider provider,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -69,7 +70,7 @@ contract LiquidityProviderSandbox is
onlyOwner
override
{
ILiquidityProvider(provider).sellTokenForToken(
provider.sellTokenForToken(
inputToken,
outputToken,
recipient,
@@ -86,8 +87,8 @@ contract LiquidityProviderSandbox is
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellEthForToken(
address provider,
address outputToken,
ILiquidityProvider provider,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -96,7 +97,7 @@ contract LiquidityProviderSandbox is
onlyOwner
override
{
ILiquidityProvider(provider).sellEthForToken(
provider.sellEthForToken(
outputToken,
recipient,
minBuyAmount,
@@ -112,8 +113,8 @@ contract LiquidityProviderSandbox is
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForEth(
address provider,
address inputToken,
ILiquidityProvider provider,
IERC20TokenV06 inputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -122,7 +123,7 @@ contract LiquidityProviderSandbox is
onlyOwner
override
{
ILiquidityProvider(provider).sellTokenForEth(
provider.sellTokenForEth(
inputToken,
payable(recipient),
minBuyAmount,

View File

@@ -20,10 +20,23 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../vendor/ILiquidityProvider.sol";
/// @dev Feature to swap directly with an on-chain liquidity provider.
interface ILiquidityProviderFeature {
/// @dev Event for data pipeline.
event LiquidityProviderSwap(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
ILiquidityProvider provider,
address recipient
);
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
/// at the given `provider` address.
/// @param inputToken The token being sold.
@@ -38,9 +51,9 @@ interface ILiquidityProviderFeature {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellToLiquidityProvider(
address inputToken,
address outputToken,
address payable provider,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
ILiquidityProvider provider,
address recipient,
uint256 sellAmount,
uint256 minBuyAmount,

View File

@@ -23,12 +23,14 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../errors/LibLiquidityProviderRichErrors.sol";
import "../external/ILiquidityProviderSandbox.sol";
import "../external/LiquidityProviderSandbox.sol";
import "../fixins/FixinCommon.sol";
import "../fixins/FixinTokenSpender.sol";
import "../migrations/LibMigrate.sol";
import "../transformers/LibERC20Transformer.sol";
import "./IFeature.sol";
import "./ILiquidityProviderFeature.sol";
@@ -45,23 +47,11 @@ contract LiquidityProviderFeature is
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "LiquidityProviderFeature";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 2);
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 3);
/// @dev ETH pseudo-token address.
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev The sandbox contract address.
ILiquidityProviderSandbox public immutable sandbox;
/// @dev Event for data pipeline.
event LiquidityProviderSwap(
address inputToken,
address outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
address provider,
address recipient
);
constructor(LiquidityProviderSandbox sandbox_, bytes32 greedyTokensBloomFilter)
public
FixinCommon()
@@ -95,9 +85,9 @@ contract LiquidityProviderFeature is
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellToLiquidityProvider(
address inputToken,
address outputToken,
address payable provider,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
ILiquidityProvider provider,
address recipient,
uint256 sellAmount,
uint256 minBuyAmount,
@@ -114,21 +104,21 @@ contract LiquidityProviderFeature is
// Forward all attached ETH to the provider.
if (msg.value > 0) {
provider.transfer(msg.value);
payable(address(provider)).transfer(msg.value);
}
if (inputToken != ETH_TOKEN_ADDRESS) {
if (!LibERC20Transformer.isTokenETH(inputToken)) {
// Transfer input ERC20 tokens to the provider.
_transferERC20Tokens(
IERC20TokenV06(inputToken),
inputToken,
msg.sender,
provider,
address(provider),
sellAmount
);
}
if (inputToken == ETH_TOKEN_ADDRESS) {
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
if (LibERC20Transformer.isTokenETH(inputToken)) {
uint256 balanceBefore = outputToken.balanceOf(recipient);
sandbox.executeSellEthForToken(
provider,
outputToken,
@@ -137,7 +127,7 @@ contract LiquidityProviderFeature is
auxiliaryData
);
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
} else if (outputToken == ETH_TOKEN_ADDRESS) {
} else if (LibERC20Transformer.isTokenETH(outputToken)) {
uint256 balanceBefore = recipient.balance;
sandbox.executeSellTokenForEth(
provider,
@@ -148,7 +138,7 @@ contract LiquidityProviderFeature is
);
boughtAmount = recipient.balance.safeSub(balanceBefore);
} else {
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
uint256 balanceBefore = outputToken.balanceOf(recipient);
sandbox.executeSellTokenForToken(
provider,
inputToken,
@@ -157,14 +147,14 @@ contract LiquidityProviderFeature is
minBuyAmount,
auxiliaryData
);
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
boughtAmount = outputToken.balanceOf(recipient).safeSub(balanceBefore);
}
if (boughtAmount < minBuyAmount) {
LibLiquidityProviderRichErrors.LiquidityProviderIncompleteSellError(
provider,
outputToken,
inputToken,
address(provider),
address(outputToken),
address(inputToken),
sellAmount,
boughtAmount,
minBuyAmount

View File

@@ -0,0 +1,208 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../transformers/LibERC20Transformer.sol";
import "../vendor/ILiquidityProvider.sol";
contract CurveLiquidityProvider is
ILiquidityProvider
{
using LibERC20TokenV06 for IERC20TokenV06;
using LibSafeMathV06 for uint256;
using LibRichErrorsV06 for bytes;
struct CurveData {
address curveAddress;
bytes4 exchangeFunctionSelector;
int128 fromCoinIdx;
int128 toCoinIdx;
}
/// @dev This contract must be payable because takers can transfer funds
/// in prior to calling the swap function.
receive() external payable {}
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
/// to sell must be transferred to the contract prior to calling this
/// function to trigger the trade.
/// @param inputToken The token being sold.
/// @param outputToken The token being bought.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellTokenForToken(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
override
returns (uint256 boughtAmount)
{
require(
!LibERC20Transformer.isTokenETH(inputToken)
&& !LibERC20Transformer.isTokenETH(outputToken),
"CurveLiquidityProvider/INVALID_ARGS"
);
boughtAmount = _executeSwap(
inputToken,
outputToken,
minBuyAmount,
abi.decode(auxiliaryData, (CurveData))
);
// Every pool contract currently checks this but why not.
require(boughtAmount >= minBuyAmount, "CurveLiquidityProvider/UNDERBOUGHT");
outputToken.compatTransfer(recipient, boughtAmount);
}
/// @dev Trades ETH for token. ETH must either be attached to this function
/// call or sent to the contract prior to calling this function to
/// trigger the trade.
/// @param outputToken The token being bought.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellEthForToken(
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
payable
override
returns (uint256 boughtAmount)
{
require(
!LibERC20Transformer.isTokenETH(outputToken),
"CurveLiquidityProvider/INVALID_ARGS"
);
boughtAmount = _executeSwap(
LibERC20Transformer.ETH_TOKEN,
outputToken,
minBuyAmount,
abi.decode(auxiliaryData, (CurveData))
);
// Every pool contract currently checks this but why not.
require(boughtAmount >= minBuyAmount, "CurveLiquidityProvider/UNDERBOUGHT");
outputToken.compatTransfer(recipient, boughtAmount);
}
/// @dev Trades token for ETH. The token must be sent to the contract prior
/// to calling this function to trigger the trade.
/// @param inputToken The token being sold.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of ETH bought.
function sellTokenForEth(
IERC20TokenV06 inputToken,
address payable recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
override
returns (uint256 boughtAmount)
{
require(
!LibERC20Transformer.isTokenETH(inputToken),
"CurveLiquidityProvider/INVALID_ARGS"
);
boughtAmount = _executeSwap(
inputToken,
LibERC20Transformer.ETH_TOKEN,
minBuyAmount,
abi.decode(auxiliaryData, (CurveData))
);
// Every pool contract currently checks this but why not.
require(boughtAmount >= minBuyAmount, "CurveLiquidityProvider/UNDERBOUGHT");
recipient.transfer(boughtAmount);
}
/// @dev Quotes the amount of `outputToken` that would be obtained by
/// selling `sellAmount` of `inputToken`.
function getSellQuote(
IERC20TokenV06 /* inputToken */,
IERC20TokenV06 /* outputToken */,
uint256 /* sellAmount */
)
external
view
override
returns (uint256)
{
revert("CurveLiquidityProvider/NOT_IMPLEMENTED");
}
/// @dev Perform the swap against the curve pool. Handles any combination of
/// tokens
function _executeSwap(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 minBuyAmount,
CurveData memory data
)
private
returns (uint256 boughtAmount)
{
uint256 sellAmount =
LibERC20Transformer.getTokenBalanceOf(inputToken, address(this));
if (!LibERC20Transformer.isTokenETH(inputToken)) {
inputToken.approveIfBelow(data.curveAddress, sellAmount);
}
(bool success, bytes memory resultData) =
data.curveAddress.call
{ value: LibERC20Transformer.isTokenETH(inputToken) ? sellAmount : 0 }
(abi.encodeWithSelector(
data.exchangeFunctionSelector,
data.fromCoinIdx,
data.toCoinIdx,
// dx
sellAmount,
// min dy
minBuyAmount
));
if (!success) {
resultData.rrevert();
}
if (resultData.length == 32) {
// Pool returned a boughtAmount
boughtAmount = abi.decode(resultData, (uint256));
} else {
// Not all pool contracts return a `boughtAmount`, so we return
// our balance of the output token if it wasn't returned.
boughtAmount = LibERC20Transformer
.getTokenBalanceOf(outputToken, address(this));
}
}
}

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.
@@ -265,234 +273,187 @@ contract FillQuoteTransformer is
// Refund unspent protocol fees.
if (state.ethRemaining > 0 && data.refundReceiver != address(0)) {
bool transferSuccess;
if (data.refundReceiver == REFUND_RECEIVER_TAKER) {
context.taker.transfer(state.ethRemaining);
(transferSuccess,) = context.taker.call{value: state.ethRemaining}("");
} else if (data.refundReceiver == REFUND_RECEIVER_SENDER) {
context.sender.transfer(state.ethRemaining);
(transferSuccess,) = context.sender.call{value: state.ethRemaining}("");
} else {
data.refundReceiver.transfer(state.ethRemaining);
(transferSuccess,) = data.refundReceiver.call{value: state.ethRemaining}("");
}
require(transferSuccess, "FillQuoteTransformer/ETHER_TRANSFER_FALIED");
}
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

@@ -0,0 +1,68 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "../errors/LibTransformERC20RichErrors.sol";
import "./Transformer.sol";
import "./LibERC20Transformer.sol";
/// @dev A transformer that transfers tokens to arbitrary addresses.
contract PositiveSlippageFeeTransformer is
Transformer
{
using LibRichErrorsV06 for bytes;
using LibSafeMathV06 for uint256;
using LibERC20Transformer for IERC20TokenV06;
/// @dev Information for a single fee.
struct TokenFee {
// The token to transfer to `recipient`.
IERC20TokenV06 token;
// Amount of each `token` to transfer to `recipient`.
uint256 bestCaseAmount;
// Recipient of `token`.
address payable recipient;
}
/// @dev Transfers tokens to recipients.
/// @param context Context information.
/// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`).
function transform(TransformContext calldata context)
external
override
returns (bytes4 success)
{
TokenFee memory fee = abi.decode(context.data, (TokenFee));
uint256 transformerAmount = LibERC20Transformer.getTokenBalanceOf(fee.token, address(this));
if (transformerAmount > fee.bestCaseAmount) {
uint256 positiveSlippageAmount = transformerAmount - fee.bestCaseAmount;
fee.token.transformerTransfer(fee.recipient, positiveSlippageAmount);
}
return LibERC20Transformer.TRANSFORMER_SUCCESS;
}
}

View File

@@ -20,13 +20,15 @@
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";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinCryptoCom.sol";
import "./mixins/MixinDodo.sol";
import "./mixins/MixinDodoV2.sol";
import "./mixins/MixinKyber.sol";
import "./mixins/MixinMooniswap.sol";
import "./mixins/MixinMStable.sol";
@@ -38,13 +40,14 @@ import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinZeroExBridge.sol";
contract BridgeAdapter is
MixinAdapterAddresses,
IBridgeAdapter,
MixinBalancer,
MixinBancor,
MixinCoFiX,
MixinCurve,
MixinCryptoCom,
MixinDodo,
MixinDodoV2,
MixinKyber,
MixinMooniswap,
MixinMStable,
@@ -55,203 +58,154 @@ 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()
MixinDodoV2()
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 ||
order.source == BridgeSource.LINKSWAP) {
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.DODOV2) {
boughtAmount = _tradeDodoV2(
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,47 @@
// 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;
uint256 constant internal DODOV2 = 18;
uint256 constant internal LINKSWAP = 19;
// 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

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../IBridgeAdapter.sol";
interface IDODOV2 {
function sellBase(address recipient)
external
returns (uint256);
function sellQuote(address recipient)
external
returns (uint256);
}
contract MixinDodoV2 {
using LibERC20TokenV06 for IERC20TokenV06;
function _tradeDodoV2(
IERC20TokenV06 sellToken,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
(IDODOV2 pool, bool isSellBase) =
abi.decode(bridgeData, (IDODOV2, bool));
// Transfer the tokens into the pool
sellToken.compatTransfer(address(pool), sellAmount);
boughtAmount = isSellBase ?
pool.sellBase(address(this))
: pool.sellQuote(address(this));
}
}

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(
address(sellToken),
address(buyToken),
boughtAmount = provider.sellTokenForToken(
sellToken,
buyToken,
address(this), // recipient
1, // minBuyAmount
bridgeData
lpData
);
}
}

View File

@@ -19,6 +19,9 @@
pragma solidity ^0.6.5;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
interface ILiquidityProvider {
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
@@ -31,8 +34,8 @@ interface ILiquidityProvider {
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellTokenForToken(
address inputToken,
address outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -49,7 +52,7 @@ interface ILiquidityProvider {
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellEthForToken(
address outputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -66,7 +69,7 @@ interface ILiquidityProvider {
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of ETH bought.
function sellTokenForEth(
address inputToken,
IERC20TokenV06 inputToken,
address payable recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -83,8 +86,8 @@ interface ILiquidityProvider {
/// @param sellAmount Amount of `inputToken` to sell.
/// @return outputTokenAmount Amount of `outputToken` that would be obtained.
function getSellQuote(
address inputToken,
address outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 sellAmount
)
external

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

@@ -0,0 +1,100 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./TestMintableERC20Token.sol";
contract TestCurve {
event CurveCalled(
uint256 value,
bytes4 selector,
int128 fromCoinIdx,
int128 toCoinIdx,
uint256 sellAmount,
uint256 minBuyAmount
);
// The lower 16 bits of the selector are reserved for flags.
bytes4 public constant BASE_SWAP_SELECTOR = 0x12340000;
bytes4 public constant RETURN_BOUGHT_AMOUNT_SELECTOR_FLAG = 0x00000001;
int128 public constant SELL_TOKEN_COIN_IDX = 0;
int128 public constant BUY_TOKEN_COIN_IDX = 1;
int128 public constant ETH_COIN_IDX = 2;
uint256 public buyAmount;
IERC20TokenV06 public sellToken;
TestMintableERC20Token public buyToken;
constructor(
IERC20TokenV06 sellToken_,
TestMintableERC20Token buyToken_,
uint256 buyAmount_
)
public
payable
{
sellToken = sellToken_;
buyToken = buyToken_;
buyAmount = buyAmount_;
}
receive() external payable {}
fallback() external payable {
bytes4 selector = abi.decode(msg.data, (bytes4));
bool shouldReturnBoughtAmount =
(selector & RETURN_BOUGHT_AMOUNT_SELECTOR_FLAG) != 0x0;
bytes4 baseSelector = selector & 0xffff0000;
require(baseSelector == BASE_SWAP_SELECTOR, "TestCurve/REVERT");
(
int128 fromCoinIdx,
int128 toCoinIdx,
uint256 sellAmount,
uint256 minBuyAmount
) = abi.decode(msg.data[4:], (int128, int128, uint256, uint256));
if (fromCoinIdx == SELL_TOKEN_COIN_IDX) {
sellToken.transferFrom(msg.sender, address(this), sellAmount);
}
if (toCoinIdx == BUY_TOKEN_COIN_IDX) {
buyToken.mint(msg.sender, buyAmount);
} else if (toCoinIdx == ETH_COIN_IDX) {
msg.sender.transfer(buyAmount);
}
emit CurveCalled(
msg.value,
selector,
fromCoinIdx,
toCoinIdx,
sellAmount,
minBuyAmount
);
if (shouldReturnBoughtAmount) {
assembly {
mstore(0, sload(buyAmount_slot))
return(0, 32)
}
}
assembly { return(0, 0) }
}
}

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,17 +65,16 @@ 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)
returns (uint256)
{
emit SellTokenForToken(
inputToken,
@@ -91,16 +90,15 @@ 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)
returns (uint256)
{
emit SellEthForToken(
outputToken,
@@ -115,16 +113,15 @@ 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)
returns (uint256)
{
emit SellTokenForEth(
inputToken,

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-zero-ex",
"version": "0.18.1",
"version": "0.19.0",
"engines": {
"node": ">=6.12"
},
@@ -41,9 +41,9 @@
"rollback": "node ./lib/scripts/rollback.js"
},
"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",
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider",
"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|CurveLiquidityProvider|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|MixinDodoV2|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|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.11.0",
"@0x/contracts-erc20": "^3.3.4",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.20",
"@0x/contracts-test-utils": "^5.3.22",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.15",
"@0x/order-utils": "^10.4.17",
"@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.3.0",
"@0x/subproviders": "^6.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -7,6 +7,7 @@ import { ContractArtifact } from 'ethereum-types';
import * as AffiliateFeeTransformer from '../generated-artifacts/AffiliateFeeTransformer.json';
import * as BridgeAdapter from '../generated-artifacts/BridgeAdapter.json';
import * as CurveLiquidityProvider from '../generated-artifacts/CurveLiquidityProvider.json';
import * as FeeCollector from '../generated-artifacts/FeeCollector.json';
import * as FeeCollectorController from '../generated-artifacts/FeeCollectorController.json';
import * as FillQuoteTransformer from '../generated-artifacts/FillQuoteTransformer.json';
@@ -28,6 +29,7 @@ import * as MetaTransactionsFeature from '../generated-artifacts/MetaTransaction
import * as NativeOrdersFeature from '../generated-artifacts/NativeOrdersFeature.json';
import * as OwnableFeature from '../generated-artifacts/OwnableFeature.json';
import * as PayTakerTransformer from '../generated-artifacts/PayTakerTransformer.json';
import * as PositiveSlippageFeeTransformer from '../generated-artifacts/PositiveSlippageFeeTransformer.json';
import * as SimpleFunctionRegistryFeature from '../generated-artifacts/SimpleFunctionRegistryFeature.json';
import * as TokenSpenderFeature from '../generated-artifacts/TokenSpenderFeature.json';
import * as TransformERC20Feature from '../generated-artifacts/TransformERC20Feature.json';
@@ -47,6 +49,7 @@ export const artifacts = {
ITransformERC20Feature: ITransformERC20Feature as ContractArtifact,
FillQuoteTransformer: FillQuoteTransformer as ContractArtifact,
PayTakerTransformer: PayTakerTransformer as ContractArtifact,
PositiveSlippageFeeTransformer: PositiveSlippageFeeTransformer as ContractArtifact,
WethTransformer: WethTransformer as ContractArtifact,
OwnableFeature: OwnableFeature as ContractArtifact,
SimpleFunctionRegistryFeature: SimpleFunctionRegistryFeature as ContractArtifact,
@@ -62,4 +65,5 @@ export const artifacts = {
INativeOrdersFeature: INativeOrdersFeature as ContractArtifact,
FeeCollectorController: FeeCollectorController as ContractArtifact,
FeeCollector: FeeCollector as ContractArtifact,
CurveLiquidityProvider: CurveLiquidityProvider as ContractArtifact,
};

View File

@@ -46,6 +46,7 @@ export {
IZeroExContract,
LogMetadataTransformerContract,
PayTakerTransformerContract,
PositiveSlippageFeeTransformerContract,
WethTransformerContract,
ZeroExContract,
} from './wrappers';

View File

@@ -5,6 +5,7 @@
*/
export * from '../generated-wrappers/affiliate_fee_transformer';
export * from '../generated-wrappers/bridge_adapter';
export * from '../generated-wrappers/curve_liquidity_provider';
export * from '../generated-wrappers/fee_collector';
export * from '../generated-wrappers/fee_collector_controller';
export * from '../generated-wrappers/fill_quote_transformer';
@@ -26,6 +27,7 @@ export * from '../generated-wrappers/meta_transactions_feature';
export * from '../generated-wrappers/native_orders_feature';
export * from '../generated-wrappers/ownable_feature';
export * from '../generated-wrappers/pay_taker_transformer';
export * from '../generated-wrappers/positive_slippage_fee_transformer';
export * from '../generated-wrappers/simple_function_registry_feature';
export * from '../generated-wrappers/token_spender_feature';
export * from '../generated-wrappers/transform_erc20_feature';

View File

@@ -9,6 +9,8 @@ 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 CurveLiquidityProvider from '../test/generated-artifacts/CurveLiquidityProvider.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 +26,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 +53,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,13 +72,13 @@ 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';
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
import * as MixinDodoV2 from '../test/generated-artifacts/MixinDodoV2.json';
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
@@ -93,9 +92,11 @@ import * as NativeOrdersFeature from '../test/generated-artifacts/NativeOrdersFe
import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json';
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
import * as PermissionlessTransformerDeployer from '../test/generated-artifacts/PermissionlessTransformerDeployer.json';
import * as PositiveSlippageFeeTransformer from '../test/generated-artifacts/PositiveSlippageFeeTransformer.json';
import * as SimpleFunctionRegistryFeature from '../test/generated-artifacts/SimpleFunctionRegistryFeature.json';
import * as TestBridge from '../test/generated-artifacts/TestBridge.json';
import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.json';
import * as TestCurve from '../test/generated-artifacts/TestCurve.json';
import * as TestDelegateCaller from '../test/generated-artifacts/TestDelegateCaller.json';
import * as TestFeeCollectorController from '../test/generated-artifacts/TestFeeCollectorController.json';
import * as TestFillQuoteTransformerBridge from '../test/generated-artifacts/TestFillQuoteTransformerBridge.json';
@@ -189,6 +190,7 @@ export const artifacts = {
FixinProtocolFees: FixinProtocolFees as ContractArtifact,
FixinReentrancyGuard: FixinReentrancyGuard as ContractArtifact,
FixinTokenSpender: FixinTokenSpender as ContractArtifact,
CurveLiquidityProvider: CurveLiquidityProvider as ContractArtifact,
FullMigration: FullMigration as ContractArtifact,
InitialMigration: InitialMigration as ContractArtifact,
LibBootstrap: LibBootstrap as ContractArtifact,
@@ -208,17 +210,19 @@ export const artifacts = {
LibERC20Transformer: LibERC20Transformer as ContractArtifact,
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
PayTakerTransformer: PayTakerTransformer as ContractArtifact,
PositiveSlippageFeeTransformer: PositiveSlippageFeeTransformer as ContractArtifact,
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,
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
MixinCurve: MixinCurve as ContractArtifact,
MixinDodo: MixinDodo as ContractArtifact,
MixinDodoV2: MixinDodoV2 as ContractArtifact,
MixinKyber: MixinKyber as ContractArtifact,
MixinMStable: MixinMStable as ContractArtifact,
MixinMooniswap: MixinMooniswap as ContractArtifact,
@@ -230,13 +234,11 @@ 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,
TestCurve: TestCurve as ContractArtifact,
TestDelegateCaller: TestDelegateCaller as ContractArtifact,
TestFeeCollectorController: TestFeeCollectorController as ContractArtifact,
TestFillQuoteTransformerBridge: TestFillQuoteTransformerBridge as ContractArtifact,

View File

@@ -0,0 +1,294 @@
import { blockchainTests, constants, expect, getRandomInteger, verifyEventsFromLogs } from '@0x/contracts-test-utils';
import { BigNumber, hexUtils } from '@0x/utils';
import { artifacts } from '../artifacts';
import { CurveLiquidityProviderContract, TestCurveContract, TestMintableERC20TokenContract } from '../wrappers';
blockchainTests.resets('CurveLiquidityProvider feature', env => {
let lp: CurveLiquidityProviderContract;
let sellToken: TestMintableERC20TokenContract;
let buyToken: TestMintableERC20TokenContract;
let testCurve: TestCurveContract;
let owner: string;
let taker: string;
const RECIPIENT = hexUtils.random(20);
const SELL_AMOUNT = getRandomInteger('1e6', '1e18');
const BUY_AMOUNT = getRandomInteger('1e6', '10e18');
const REVERTING_SELECTOR = '0xdeaddead';
const SWAP_SELECTOR = '0x12340000';
const SWAP_WITH_RETURN_SELECTOR = '0x12340001';
const ETH_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
const SELL_TOKEN_COIN_IDX = 0;
const BUY_TOKEN_COIN_IDX = 1;
const ETH_COIN_IDX = 2;
const { ZERO_AMOUNT } = constants;
before(async () => {
[owner, taker] = await env.getAccountAddressesAsync();
[sellToken, buyToken] = await Promise.all(
new Array(2)
.fill(0)
.map(async () =>
TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestMintableERC20Token,
env.provider,
env.txDefaults,
artifacts,
),
),
);
testCurve = await TestCurveContract.deployFrom0xArtifactAsync(
artifacts.TestCurve,
env.provider,
{ ...env.txDefaults, value: BUY_AMOUNT },
artifacts,
sellToken.address,
buyToken.address,
BUY_AMOUNT,
);
lp = await CurveLiquidityProviderContract.deployFrom0xArtifactAsync(
artifacts.CurveLiquidityProvider,
env.provider,
{ ...env.txDefaults, from: taker },
artifacts,
);
});
interface CurveDataFields {
curveAddress: string;
exchangeFunctionSelector: string;
fromCoinIdx: number;
toCoinIdx: number;
}
async function fundProviderContractAsync(fromCoinIdx: number, amount: BigNumber = SELL_AMOUNT): Promise<void> {
if (fromCoinIdx === SELL_TOKEN_COIN_IDX) {
await sellToken.mint(lp.address, SELL_AMOUNT).awaitTransactionSuccessAsync();
} else {
await env.web3Wrapper.awaitTransactionSuccessAsync(
await env.web3Wrapper.sendTransactionAsync({
from: taker,
to: lp.address,
value: SELL_AMOUNT,
}),
);
}
}
function encodeCurveData(fields: Partial<CurveDataFields> = {}): string {
const _fields = {
curveAddress: testCurve.address,
exchangeFunctionSelector: SWAP_SELECTOR,
fromCoinIdx: SELL_TOKEN_COIN_IDX,
toCoinIdx: BUY_TOKEN_COIN_IDX,
...fields,
};
return hexUtils.concat(
hexUtils.leftPad(_fields.curveAddress),
hexUtils.rightPad(_fields.exchangeFunctionSelector),
hexUtils.leftPad(_fields.fromCoinIdx),
hexUtils.leftPad(_fields.toCoinIdx),
);
}
it('can swap ERC20->ERC20', async () => {
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
const call = lp.sellTokenForToken(
sellToken.address,
buyToken.address,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData(),
);
const boughtAmount = await call.callAsync();
const { logs } = await call.awaitTransactionSuccessAsync();
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
verifyEventsFromLogs(
logs,
[
{
value: ZERO_AMOUNT,
selector: SWAP_SELECTOR,
fromCoinIdx: new BigNumber(SELL_TOKEN_COIN_IDX),
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
sellAmount: SELL_AMOUNT,
minBuyAmount: BUY_AMOUNT,
},
],
'CurveCalled',
);
});
it('can swap ERC20->ETH', async () => {
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
const call = lp.sellTokenForEth(
sellToken.address,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData({ toCoinIdx: ETH_COIN_IDX }),
);
const boughtAmount = await call.callAsync();
const { logs } = await call.awaitTransactionSuccessAsync();
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
expect(await env.web3Wrapper.getBalanceInWeiAsync(RECIPIENT)).to.bignumber.eq(BUY_AMOUNT);
verifyEventsFromLogs(
logs,
[
{
value: ZERO_AMOUNT,
selector: SWAP_SELECTOR,
fromCoinIdx: new BigNumber(SELL_TOKEN_COIN_IDX),
toCoinIdx: new BigNumber(ETH_COIN_IDX),
sellAmount: SELL_AMOUNT,
minBuyAmount: BUY_AMOUNT,
},
],
'CurveCalled',
);
});
it('can swap ETH->ERC20', async () => {
await fundProviderContractAsync(ETH_COIN_IDX);
const call = lp.sellEthForToken(
buyToken.address,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData({ fromCoinIdx: ETH_COIN_IDX }),
);
const boughtAmount = await call.callAsync();
const { logs } = await call.awaitTransactionSuccessAsync();
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
verifyEventsFromLogs(
logs,
[
{
value: SELL_AMOUNT,
selector: SWAP_SELECTOR,
fromCoinIdx: new BigNumber(ETH_COIN_IDX),
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
sellAmount: SELL_AMOUNT,
minBuyAmount: BUY_AMOUNT,
},
],
'CurveCalled',
);
});
it('can swap ETH->ERC20 with attached ETH', async () => {
const call = lp.sellEthForToken(
buyToken.address,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData({ fromCoinIdx: ETH_COIN_IDX }),
);
const boughtAmount = await call.callAsync({ value: SELL_AMOUNT });
const { logs } = await call.awaitTransactionSuccessAsync({ value: SELL_AMOUNT });
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
verifyEventsFromLogs(
logs,
[
{
value: SELL_AMOUNT,
selector: SWAP_SELECTOR,
fromCoinIdx: new BigNumber(ETH_COIN_IDX),
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
sellAmount: SELL_AMOUNT,
minBuyAmount: BUY_AMOUNT,
},
],
'CurveCalled',
);
});
it('can swap with a pool that returns bought amount', async () => {
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
const call = lp.sellTokenForToken(
sellToken.address,
buyToken.address,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData({ exchangeFunctionSelector: SWAP_WITH_RETURN_SELECTOR }),
);
const boughtAmount = await call.callAsync();
const { logs } = await call.awaitTransactionSuccessAsync();
expect(boughtAmount).to.bignumber.eq(BUY_AMOUNT);
expect(await buyToken.balanceOf(RECIPIENT).callAsync()).to.bignumber.eq(BUY_AMOUNT);
verifyEventsFromLogs(
logs,
[
{
value: ZERO_AMOUNT,
selector: SWAP_WITH_RETURN_SELECTOR,
fromCoinIdx: new BigNumber(SELL_TOKEN_COIN_IDX),
toCoinIdx: new BigNumber(BUY_TOKEN_COIN_IDX),
sellAmount: SELL_AMOUNT,
minBuyAmount: BUY_AMOUNT,
},
],
'CurveCalled',
);
});
it('reverts if pool reverts', async () => {
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
const call = lp.sellTokenForToken(
sellToken.address,
buyToken.address,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData({ exchangeFunctionSelector: REVERTING_SELECTOR }),
);
return expect(call.callAsync()).to.revertWith('TestCurve/REVERT');
});
it('reverts if underbought', async () => {
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
const call = lp.sellTokenForToken(
sellToken.address,
buyToken.address,
RECIPIENT,
BUY_AMOUNT.plus(1),
encodeCurveData(),
);
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/UNDERBOUGHT');
});
it('reverts if ERC20->ERC20 receives an ETH input token', async () => {
await fundProviderContractAsync(ETH_COIN_IDX);
const call = lp.sellTokenForToken(
ETH_TOKEN_ADDRESS,
buyToken.address,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData(),
);
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
});
it('reverts if ERC20->ERC20 receives an ETH output token', async () => {
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
const call = lp.sellTokenForToken(
sellToken.address,
ETH_TOKEN_ADDRESS,
RECIPIENT,
BUY_AMOUNT,
encodeCurveData(),
);
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
});
it('reverts if ERC20->ETH receives an ETH input token', async () => {
await fundProviderContractAsync(SELL_TOKEN_COIN_IDX);
const call = lp.sellTokenForEth(ETH_TOKEN_ADDRESS, RECIPIENT, BUY_AMOUNT, encodeCurveData());
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
});
it('reverts if ETH->ERC20 receives an ETH output token', async () => {
await fundProviderContractAsync(ETH_COIN_IDX);
const call = lp.sellEthForToken(ETH_TOKEN_ADDRESS, RECIPIENT, BUY_AMOUNT, encodeCurveData());
return expect(call.callAsync()).to.revertWith('CurveLiquidityProvider/INVALID_ARGS');
});
});

View File

@@ -0,0 +1,127 @@
import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils';
import { encodePositiveSlippageFeeTransformerData } from '@0x/protocol-utils';
import { BigNumber } from '@0x/utils';
import { artifacts } from '../artifacts';
import {
PositiveSlippageFeeTransformerContract,
TestMintableERC20TokenContract,
TestTransformerHostContract,
} from '../wrappers';
const { ZERO_AMOUNT } = constants;
blockchainTests.resets('PositiveSlippageFeeTransformer', env => {
const recipient = randomAddress();
let caller: string;
let token: TestMintableERC20TokenContract;
let transformer: PositiveSlippageFeeTransformerContract;
let host: TestTransformerHostContract;
before(async () => {
[caller] = await env.getAccountAddressesAsync();
token = await TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestMintableERC20Token,
env.provider,
env.txDefaults,
artifacts,
);
transformer = await PositiveSlippageFeeTransformerContract.deployFrom0xArtifactAsync(
artifacts.PositiveSlippageFeeTransformer,
env.provider,
env.txDefaults,
artifacts,
);
host = await TestTransformerHostContract.deployFrom0xArtifactAsync(
artifacts.TestTransformerHost,
env.provider,
{ ...env.txDefaults, from: caller },
artifacts,
);
});
interface Balances {
ethBalance: BigNumber;
tokenBalance: BigNumber;
}
async function getBalancesAsync(owner: string): Promise<Balances> {
return {
ethBalance: await env.web3Wrapper.getBalanceInWeiAsync(owner),
tokenBalance: await token.balanceOf(owner).callAsync(),
};
}
async function mintHostTokensAsync(amount: BigNumber): Promise<void> {
await token.mint(host.address, amount).awaitTransactionSuccessAsync();
}
it('does not transfer positive slippage fees when bestCaseAmount is equal to amount', async () => {
const amount = getRandomInteger(1, '1e18');
const data = encodePositiveSlippageFeeTransformerData({
token: token.address,
bestCaseAmount: amount,
recipient,
});
await mintHostTokensAsync(amount);
const beforeBalanceHost = await getBalancesAsync(host.address);
const beforeBalanceRecipient = await getBalancesAsync(recipient);
await host
.rawExecuteTransform(transformer.address, {
data,
sender: randomAddress(),
taker: randomAddress(),
})
.awaitTransactionSuccessAsync();
expect(await getBalancesAsync(host.address)).to.deep.eq(beforeBalanceHost);
expect(await getBalancesAsync(recipient)).to.deep.eq(beforeBalanceRecipient);
});
it('does not transfer positive slippage fees when bestCaseAmount is higher than amount', async () => {
const amount = getRandomInteger(1, '1e18');
const bestCaseAmount = amount.times(1.1).decimalPlaces(0, BigNumber.ROUND_FLOOR);
const data = encodePositiveSlippageFeeTransformerData({
token: token.address,
bestCaseAmount,
recipient,
});
await mintHostTokensAsync(amount);
const beforeBalanceHost = await getBalancesAsync(host.address);
const beforeBalanceRecipient = await getBalancesAsync(recipient);
await host
.rawExecuteTransform(transformer.address, {
data,
sender: randomAddress(),
taker: randomAddress(),
})
.awaitTransactionSuccessAsync();
expect(await getBalancesAsync(host.address)).to.deep.eq(beforeBalanceHost);
expect(await getBalancesAsync(recipient)).to.deep.eq(beforeBalanceRecipient);
});
it('send positive slippage fee to recipient when bestCaseAmount is lower than amount', async () => {
const amount = getRandomInteger(1, '1e18');
const bestCaseAmount = amount.times(0.95).decimalPlaces(0, BigNumber.ROUND_FLOOR);
const data = encodePositiveSlippageFeeTransformerData({
token: token.address,
bestCaseAmount,
recipient,
});
await mintHostTokensAsync(amount);
await host
.rawExecuteTransform(transformer.address, {
data,
sender: randomAddress(),
taker: randomAddress(),
})
.awaitTransactionSuccessAsync();
expect(await getBalancesAsync(host.address)).to.deep.eq({
tokenBalance: bestCaseAmount,
ethBalance: ZERO_AMOUNT,
});
expect(await getBalancesAsync(recipient)).to.deep.eq({
tokenBalance: amount.minus(bestCaseAmount), // positive slippage
ethBalance: ZERO_AMOUNT,
});
});
});

View File

@@ -7,6 +7,8 @@ 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/curve_liquidity_provider';
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 +24,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 +51,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,13 +70,13 @@ 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';
export * from '../test/generated-wrappers/mixin_crypto_com';
export * from '../test/generated-wrappers/mixin_curve';
export * from '../test/generated-wrappers/mixin_dodo';
export * from '../test/generated-wrappers/mixin_dodo_v2';
export * from '../test/generated-wrappers/mixin_kyber';
export * from '../test/generated-wrappers/mixin_m_stable';
export * from '../test/generated-wrappers/mixin_mooniswap';
@@ -91,9 +90,11 @@ export * from '../test/generated-wrappers/native_orders_feature';
export * from '../test/generated-wrappers/ownable_feature';
export * from '../test/generated-wrappers/pay_taker_transformer';
export * from '../test/generated-wrappers/permissionless_transformer_deployer';
export * from '../test/generated-wrappers/positive_slippage_fee_transformer';
export * from '../test/generated-wrappers/simple_function_registry_feature';
export * from '../test/generated-wrappers/test_bridge';
export * from '../test/generated-wrappers/test_call_target';
export * from '../test/generated-wrappers/test_curve';
export * from '../test/generated-wrappers/test_delegate_caller';
export * from '../test/generated-wrappers/test_fee_collector_controller';
export * from '../test/generated-wrappers/test_fill_quote_transformer_bridge';

View File

@@ -5,6 +5,7 @@
"files": [
"generated-artifacts/AffiliateFeeTransformer.json",
"generated-artifacts/BridgeAdapter.json",
"generated-artifacts/CurveLiquidityProvider.json",
"generated-artifacts/FeeCollector.json",
"generated-artifacts/FeeCollectorController.json",
"generated-artifacts/FillQuoteTransformer.json",
@@ -26,6 +27,7 @@
"generated-artifacts/NativeOrdersFeature.json",
"generated-artifacts/OwnableFeature.json",
"generated-artifacts/PayTakerTransformer.json",
"generated-artifacts/PositiveSlippageFeeTransformer.json",
"generated-artifacts/SimpleFunctionRegistryFeature.json",
"generated-artifacts/TokenSpenderFeature.json",
"generated-artifacts/TransformERC20Feature.json",
@@ -35,6 +37,8 @@
"test/generated-artifacts/AllowanceTarget.json",
"test/generated-artifacts/BootstrapFeature.json",
"test/generated-artifacts/BridgeAdapter.json",
"test/generated-artifacts/BridgeSource.json",
"test/generated-artifacts/CurveLiquidityProvider.json",
"test/generated-artifacts/FeeCollector.json",
"test/generated-artifacts/FeeCollectorController.json",
"test/generated-artifacts/FillQuoteTransformer.json",
@@ -50,10 +54,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 +81,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,13 +100,13 @@
"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",
"test/generated-artifacts/MixinCryptoCom.json",
"test/generated-artifacts/MixinCurve.json",
"test/generated-artifacts/MixinDodo.json",
"test/generated-artifacts/MixinDodoV2.json",
"test/generated-artifacts/MixinKyber.json",
"test/generated-artifacts/MixinMStable.json",
"test/generated-artifacts/MixinMooniswap.json",
@@ -119,9 +120,11 @@
"test/generated-artifacts/OwnableFeature.json",
"test/generated-artifacts/PayTakerTransformer.json",
"test/generated-artifacts/PermissionlessTransformerDeployer.json",
"test/generated-artifacts/PositiveSlippageFeeTransformer.json",
"test/generated-artifacts/SimpleFunctionRegistryFeature.json",
"test/generated-artifacts/TestBridge.json",
"test/generated-artifacts/TestCallTarget.json",
"test/generated-artifacts/TestCurve.json",
"test/generated-artifacts/TestDelegateCaller.json",
"test/generated-artifacts/TestFeeCollectorController.json",
"test/generated-artifacts/TestFillQuoteTransformerBridge.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

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