Compare commits

..

43 Commits

Author SHA1 Message Date
Github Actions
5a15044ead Publish
- @0x/contracts-asset-proxy@3.7.9
 - @0x/contracts-broker@1.1.27
 - @0x/contracts-coordinator@3.1.28
 - @0x/contracts-dev-utils@1.3.26
 - @0x/contracts-erc1155@2.1.27
 - @0x/contracts-erc20@3.3.6
 - @0x/contracts-erc721@3.1.27
 - @0x/contracts-exchange-forwarder@4.2.28
 - @0x/contracts-exchange-libs@4.3.27
 - @0x/contracts-exchange@3.2.28
 - @0x/contracts-extensions@6.2.22
 - @0x/contracts-integrations@2.7.30
 - @0x/contracts-multisig@4.1.28
 - @0x/contracts-staking@2.0.35
 - @0x/contracts-test-utils@5.3.24
 - @0x/contracts-treasury@1.1.1
 - @0x/contracts-utils@4.7.6
 - @0x/contracts-zero-ex@0.21.0
 - @0x/asset-swapper@6.4.0
 - @0x/contract-addresses@6.0.0
 - @0x/contract-artifacts@3.14.0
 - @0x/contract-wrappers-test@12.2.39
 - @0x/contract-wrappers@13.15.0
 - @0x/migrations@8.0.0
 - @0x/order-utils@10.4.19
 - @0x/protocol-utils@1.4.0
2021-04-01 21:09:06 +00:00
Github Actions
a69d76e487 Updated CHANGELOGS & MD docs 2021-04-01 21:09:02 +00:00
Kim Persson
3adfcdffa8 Maker PSM integration [TKR-2] (#150)
* ADDS basic boilerplate for PSM bridge WIP

* ADDS integrate the MakerPSM mixin and fix incorrect naming

* fix: take into account PSM fee when buying USDC from PSM

* feat: intial stab at a PSM sampler WIP

* feat: integrate MakerPsm into AS WIP

* refactor: get VAT contract address from PSM instead of passing it in

* fix: hardcode PSM Gemtoken to USDC

* fix: remove passing in authGem, get from PSM contract instead

* fix: use constant modified to avoid using storage variables

* fix: incorrect num decimals after multiplication in sampler

* fix: PSM buy sampling

* fix: use fillData to estimate gas schedule

* Rebased on latest development

* Guard and use latest Curve LiquidityProvider

* `@0x/contract-addresses`: Redeploy FQT on mainnet and ropsten

Co-authored-by: Jacob Evans <jacob@dekz.net>
Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
2021-04-01 15:45:06 -04:00
Lawrence Forman
164a5d44d9 bsc<->development rebase (#189)
* FQT: Pack Protocol/source name into source ID (#162)

* `@0x/contracts-zero-ex`: Encode protocol ID and source name in bridge source ID
`@0x/asset-swapper`: Use new bridge source ID encoding.

* fix linter issues

* contracts cleanup (#164)

* `@0x/contracts-zero-ex`: Add PancakeSwapFeature

* `@0x/contracts-zero-ex`: Remove tokenspender/allowance target/greedy tokens stuff.'
`@0x/contract-addresses`: Add BSC addresses. Remove exchangeProxyAllowanceTarget.
`@0x/migrations`: Remove exchangeProxyAllowanceTarget.

* Update contracts/zero-ex/contracts/src/features/IPancakeSwapFeature.sol

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

* `@0x/contracts-zero-ex`: Add sushiswap support to PancakeSwap

* `@0x/contract-artifacts`: Regenerate artifacts
`@0x/contract-wrappers`: Regenerate wrappers

* `@0x/contract-addresses`: Add BSC addresses

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

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

* feat: Better chain support (#163)

* feat: Better chain support

* feat: better chain support refactor deployment constants (#166)

* proliferate the chainId

* Refactor sampler to remove DeploymentConstants dependency and fixed addresses

* Rework WETH out, replacing with address(0)

* wat

* hack DeploymentConstants for now

* proliferate the chainId

* Refactor sampler to remove DeploymentConstants dependency and fixed addresses

* remove duped network addresses

* Rework the bridge source encoder

* Use the constants NATIVE_FEE_TOKEN in EP consumer

* `@0x/contract-addresses`: Fix WBNB address (#170)

Co-authored-by: Lawrence Forman <lawrence@0xproject.com>

* multichain enable cakez vip (#171)

* feat: Better chain support

* feat: better chain support refactor deployment constants (#166)

* proliferate the chainId

* Refactor sampler to remove DeploymentConstants dependency and fixed addresses

* Rework WETH out, replacing with address(0)

* wat

* hack DeploymentConstants for now

* proliferate the chainId

* Refactor sampler to remove DeploymentConstants dependency and fixed addresses

* remove duped network addresses

* `asset-swapper`: enable pancake VIP route generation

Co-authored-by: Jacob Evans <jacob@dekz.net>
Co-authored-by: Lawrence Forman <me@merklejerk.com>

* `@0x/contracts-zero-ex`: Fix `PancakeSwapFeature` sushi values (#172)

* `@0x/contracts-zero-ex`: Fix `PancakeSwapFeature` sushi values

* `@0x/contracts-zero-ex`: I am a bad protocologist

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

* feat: BSC Nerve + Dodo + Nerve + Ellipsis (#181)

* feat: BSC Nerve + DODO v1

* CHANGELOGs

* Remove extra balance fetch

* Add Belt

* Added Ellipsis

* Update FQT address

* `@0x/contracts-zero-ex`: Delete TokenSpenderFeature and get stuff compiling

* `@0x/asset-swapper`: fix compilation

* prettier

* `@0x/asset-swapper`: Truncate LiquidityProvider source ID name

* Update packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts

Co-authored-by: Jacob Evans <jacob@dekz.net>

* Update packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts

Co-authored-by: Jacob Evans <jacob@dekz.net>

* `@0x/contracts-zero-ex`: Fix BakerySwap on PackageSwapFeature (#190)

* address review comments

Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>
Co-authored-by: Jacob Evans <jacob@dekz.net>
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-03-31 18:49:44 -04:00
phil-ociraptor
70ddab0231 [MKR-3] Prepare Asset Swapper for RFQM (#187)
* Prepare QuoteRequestor for RFQM

* Add unit tests for Quote Requestor changes

* Fix lint errors
2021-03-31 12:11:10 -05:00
Xianny
7bf009fbf6 Upgrade to typescript v4.2.2 (#188)
* upgrade to typescript v4.2.2

* prettier; remove outdated test
2021-03-30 13:26:05 -07:00
Daniel Pyrathon
525bc8197b Revive quote report (#184)
* Revives Quote Report

* prettier

* Remove unused parameters

* updated a few issues with tests

* Remove old code

* Fixed other unit tests
2021-03-30 09:57:03 -07:00
Alex Kroeger
24397c51a8 improve logging for alt rfq request (#158)
* improve logging for alt rfq request

* clean up unsuccessful status code logic

* Fix quote requestor tests

* get rid of unnecessary promise handling

* remove unused code

* update changelog

* changed warning message for no quote

* appease prettier
2021-03-24 13:45:54 -07:00
phil-ociraptor
06b3464756 Rename {Rfqt=>Rfq} for types in Asset Swapper (#179)
* Rename {Rfqt=>Rfq} for types in Asset Swapper

* PR edit 1 - fix build errors

* PR edit 2 - rename mocked types used in tests

* PR edit 3 - fix broken test build

* PR edit 4 - rename SwapQuoterRfqOpts and add changelog entry
2021-03-23 17:21:50 -05:00
phil-ociraptor
bbaa90bd9a Add a cancel token to manually enforce a timeout in Quote Requestor (#176)
* Add a cancel token to manually enforce a timeout in Quote Requestor

* Start setTimeout before making requests, add an extra buffer

* Run prettier

* Add comment to changelog
2021-03-22 17:08:51 -05:00
mzhu25
5c683cbc0f Fix Multiplex multi-hop encoding issue (#178) 2021-03-17 22:28:35 -07:00
Alex Kroeger
95345f18bc use the RfqOrder source flag for comparison price EP overhead (#177)
* use the RfqOrder source flag for comparison price EP overhead

* updated changelog

* changelog -> 6.4
2021-03-17 16:37:56 -07:00
Github Actions
4c3fbe83ac Publish
- @0x/contracts-asset-proxy@3.7.8
 - @0x/contracts-broker@1.1.26
 - @0x/contracts-coordinator@3.1.27
 - @0x/contracts-dev-utils@1.3.25
 - @0x/contracts-erc1155@2.1.26
 - @0x/contracts-erc20@3.3.5
 - @0x/contracts-erc721@3.1.26
 - @0x/contracts-exchange-forwarder@4.2.27
 - @0x/contracts-exchange-libs@4.3.26
 - @0x/contracts-exchange@3.2.27
 - @0x/contracts-extensions@6.2.21
 - @0x/contracts-integrations@2.7.29
 - @0x/contracts-multisig@4.1.27
 - @0x/contracts-staking@2.0.34
 - @0x/contracts-test-utils@5.3.23
 - @0x/contracts-treasury@1.1.0
 - @0x/contracts-utils@4.7.5
 - @0x/contracts-zero-ex@0.20.0
 - @0x/asset-swapper@6.3.0
 - @0x/contract-artifacts@3.13.0
 - @0x/contract-wrappers-test@12.2.38
 - @0x/contract-wrappers@13.14.0
 - @0x/migrations@7.0.1
 - @0x/order-utils@10.4.18
 - @0x/protocol-utils@1.3.1
2021-03-17 18:23:51 +00:00
Github Actions
7caa43d02c Updated CHANGELOGS & MD docs 2021-03-17 18:23:47 +00:00
mzhu25
3d4c03c9df Update asset-swapper to support MultiplexFeature (#168)
* Update asset-swapper to support MultiplexFeature

* Address PR feedback

* Update changelogs
2021-03-16 22:20:33 -07:00
Lawrence Forman
22e1ed35d3 docs: Fix EIP712 hashing docs for limit and RFQ orders (#173) 2021-03-16 15:09:00 -04:00
Alex Kroeger
dabe6fd793 add tx origin blacklist to RFQ options (#169)
* add tx origin blacklist to RFQ options

* Fix typo

* use set instead of array

* make sure tx origin is lower case

* changed default blacklist value from array to set
2021-03-11 18:05:16 -08:00
mzhu25
3cc639c8d0 MultiplexFeature and BatchFillNativeOrdersFeature (#140)
* WrappedFillFeature

* Address internal feedback

* create features/interfaces/ directory

* Split NativeOrdersFeature into mixins

* Rename mixins to use NativeOrders namespace

* Add BatchFillNativeOrdersFeature

* Rename WrapperFillFeature => MultiplexFeature and add natspec comments

* Emit LiquidityProviderSwap event

* post-rebase fixes

* Multiplex mainnet fork tests

* lint

* Add tests for batch fill functions

* Remove market functions

* Addres PR feedback

* Remove nested _batchFill calls from _multiHopFill

* Add BatchFillIncompleteRevertError type

* Use call{value: amount}() instead of transfer(amount)

* Remove outdated comment

* Update some comments

* Add events

* Address spot-check recommendations

* Remove-top level events, add ExpiredRfqOrder event

* Update changelog

* Change ExpiredRfqOrder event

* Update IZeroEx artifact and contract wrapper
2021-03-08 15:45:49 -08:00
mzhu25
22c8e0b6db Make the proposal/quorum thresholds updatable (#165)
* Make the proposal/quorum thresholds updatable

* Test threshold updating
2021-03-04 10:56:37 -08:00
Oskar Paolini
f3ca4293bc feat: add proxy configuration to axios instance in RFQT asset-swapper (#159)
* add proxy configuration to axios instance

* add support for additional axios instance opts

* move quoteRequestorHttpClient parameter

* fix tests, build errors

* prettier

* bump axios

* bumped mock-axios-adapter version

* downgrade axios again

* re-upgrade axios 🤦

* updated yarn.lock

* updated changelog

Co-authored-by: Alex Kroeger <alexrkroeger@gmail.com>
2021-03-03 11:38:54 -08:00
Lawrence Forman
db3e076d03 update deps and publish gh action for prerelease support 2021-03-03 01:16:22 -05:00
Lawrence Forman
1a6759820a Mooniswap LP (#143)
* `@0x/asset-swapper`: Fix compiler error on `ILiquidityProvider` call
`@0x/protocol-utils`: Add VIP utils.

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

* `@0x/contracts-zero-ex`: Add `MooniswapLiquidityProvider`.
`@0x/asset-swapper`: Add Mooniswap "vip" to EP quote consumer.

* rebase and prettier

* fix linter error

* `@0x/contracts-zero-ex`: Add `MooniswapLiquidityProvider` tests.

* review feedback

* `@0x/contracts-zero-ex`: Emit `LiquidityProviderFill` events in LPs

* `@0x/asset-swapper`: Fix compilation error

* `@0x/asset-swapper`: Add EP gas overhead to Curve and Mooni LP bridge routes

* `@0x/asset-swapper`: Remove consumer gas overhead for LP VIPs

* `@0x/contracts-zero-ex`: Add more params to `LiquidityProviderFill` event

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

* `@0x/asset-swapper`: Update deployed Curve and Mooni LPs

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-03-02 16:50:37 -05:00
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
292 changed files with 14582 additions and 6558 deletions

View File

@@ -7,6 +7,9 @@ on:
description: 'required CI status'
default: 'success'
required: true
prerelease:
description: 'prerelease name'
required: false
jobs:
publish:
@@ -21,7 +24,7 @@ jobs:
(echo "::error ::${{ github.ref }} does not have a successful CI status" && false)
- uses: actions/checkout@v2
with:
ref: 'development'
ref: ${{ github.ref }}
fetch-depth: 0
- uses: actions/setup-node@v1
with:
@@ -41,7 +44,9 @@ jobs:
env:
NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
PUBLISH_PRERELEASE: ${{ github.event.inputs.prerelease }}
- name: 'merge into main branch'
if: github.event.inputs.prerelease == '' # unless it's a prerelease
run: |
git checkout main && \
git merge ${{ github.ref }} && \

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "3.7.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "3.7.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "3.7.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "3.7.6",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.7.9 - _April 1, 2021_
* Dependencies updated
## v3.7.8 - _March 17, 2021_
* Dependencies updated
## v3.7.7 - _February 24, 2021_
* Dependencies updated
## v3.7.6 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-asset-proxy",
"version": "3.7.6",
"version": "3.7.9",
"engines": {
"node": ">=6.12"
},
@@ -51,13 +51,13 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contract-wrappers": "^13.12.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contract-wrappers": "^13.15.0",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@types/lodash": "4.14.104",
@@ -76,15 +76,15 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/order-utils": "^10.4.16",
"@0x/contracts-erc1155": "^2.1.27",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-erc721": "^3.1.27",
"@0x/contracts-exchange-libs": "^4.3.27",
"@0x/order-utils": "^10.4.19",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",

View File

@@ -1,354 +0,0 @@
import { ContractTxFunctionObj } from '@0x/contract-wrappers';
import {
blockchainTests,
constants,
expect,
filterLogsToArguments,
getRandomInteger,
randomAddress,
shortZip,
} from '@0x/contracts-test-utils';
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { DexForwarderBridgeCall, dexForwarderBridgeDataEncoder } from '../src/dex_forwarder_bridge';
import { artifacts } from './artifacts';
import {
TestDexForwarderBridgeBridgeTransferFromCalledEventArgs as BtfCalledEventArgs,
TestDexForwarderBridgeContract,
TestDexForwarderBridgeEvents as TestEvents,
} from './wrappers';
const { ZERO_AMOUNT } = constants;
blockchainTests.resets('DexForwarderBridge unit tests', env => {
let testContract: TestDexForwarderBridgeContract;
let inputToken: string;
let outputToken: string;
const BRIDGE_SUCCESS = '0xdc1600f3';
const BRIDGE_FAILURE = '0xffffffff';
const BRIDGE_REVERT_ERROR = 'oopsie';
const NOT_AUTHORIZED_REVERT = 'DexForwarderBridge/SENDER_NOT_AUTHORIZED';
const DEFAULTS = {
toAddress: randomAddress(),
};
before(async () => {
testContract = await TestDexForwarderBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestDexForwarderBridge,
env.provider,
env.txDefaults,
artifacts,
);
// Create test tokens.
[inputToken, outputToken] = [
await callAndTransactAsync(testContract.createToken()),
await callAndTransactAsync(testContract.createToken()),
];
await callAndTransactAsync(testContract.setAuthorized(env.txDefaults.from as string));
});
async function callAndTransactAsync<TResult>(fnCall: ContractTxFunctionObj<TResult>): Promise<TResult> {
const result = await fnCall.callAsync();
await fnCall.awaitTransactionSuccessAsync({}, { shouldValidate: false });
return result;
}
function getRandomBridgeCall(
bridgeAddress: string,
fields: Partial<DexForwarderBridgeCall> = {},
): DexForwarderBridgeCall {
return {
target: bridgeAddress,
inputTokenAmount: getRandomInteger(1, '100e18'),
outputTokenAmount: getRandomInteger(1, '100e18'),
bridgeData: hexUtils.leftPad(inputToken),
...fields,
};
}
describe('bridgeTransferFrom()', () => {
let goodBridgeCalls: DexForwarderBridgeCall[];
let revertingBridgeCall: DexForwarderBridgeCall;
let failingBridgeCall: DexForwarderBridgeCall;
let allBridgeCalls: DexForwarderBridgeCall[];
let totalFillableOutputAmount: BigNumber;
let totalFillableInputAmount: BigNumber;
let recipientOutputBalance: BigNumber;
beforeEach(async () => {
goodBridgeCalls = [];
for (let i = 0; i < 4; ++i) {
goodBridgeCalls.push(await createBridgeCallAsync({ returnCode: BRIDGE_SUCCESS }));
}
revertingBridgeCall = await createBridgeCallAsync({ revertError: BRIDGE_REVERT_ERROR });
failingBridgeCall = await createBridgeCallAsync({ returnCode: BRIDGE_FAILURE });
allBridgeCalls = _.shuffle([failingBridgeCall, revertingBridgeCall, ...goodBridgeCalls]);
totalFillableInputAmount = BigNumber.sum(...goodBridgeCalls.map(c => c.inputTokenAmount));
totalFillableOutputAmount = BigNumber.sum(...goodBridgeCalls.map(c => c.outputTokenAmount));
// Grant the taker some output tokens.
await testContract.setTokenBalance(
outputToken,
DEFAULTS.toAddress,
(recipientOutputBalance = getRandomInteger(1, '100e18')),
);
});
async function setForwarderInputBalanceAsync(amount: BigNumber): Promise<void> {
await testContract
.setTokenBalance(inputToken, testContract.address, amount)
.awaitTransactionSuccessAsync({}, { shouldValidate: false });
}
async function createBridgeCallAsync(
opts: Partial<{
returnCode: string;
revertError: string;
callFields: Partial<DexForwarderBridgeCall>;
outputFillAmount: BigNumber;
}>,
): Promise<DexForwarderBridgeCall> {
const { returnCode, revertError, callFields, outputFillAmount } = {
returnCode: BRIDGE_SUCCESS,
revertError: '',
...opts,
};
const bridge = await callAndTransactAsync(testContract.createBridge(returnCode, revertError));
const call = getRandomBridgeCall(bridge, callFields);
await testContract
.setBridgeTransferAmount(call.target, outputFillAmount || call.outputTokenAmount)
.awaitTransactionSuccessAsync({}, { shouldValidate: false });
return call;
}
async function callBridgeTransferFromAsync(opts: {
bridgeData: string;
sellAmount?: BigNumber;
buyAmount?: BigNumber;
}): Promise<DecodedLogs> {
// Fund the forwarder with input tokens to sell.
await setForwarderInputBalanceAsync(opts.sellAmount || totalFillableInputAmount);
const call = testContract.bridgeTransferFrom(
outputToken,
testContract.address,
DEFAULTS.toAddress,
opts.buyAmount || totalFillableOutputAmount,
opts.bridgeData,
);
const returnCode = await call.callAsync();
if (returnCode !== BRIDGE_SUCCESS) {
throw new Error('Expected BRIDGE_SUCCESS');
}
const receipt = await call.awaitTransactionSuccessAsync({}, { shouldValidate: false });
// tslint:disable-next-line: no-unnecessary-type-assertion
return receipt.logs as DecodedLogs;
}
it('succeeds with no bridge calls and no input balance', async () => {
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls: [],
});
await callBridgeTransferFromAsync({ bridgeData, sellAmount: ZERO_AMOUNT });
});
it('succeeds with bridge calls and no input balance', async () => {
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls: allBridgeCalls,
});
await callBridgeTransferFromAsync({ bridgeData, sellAmount: ZERO_AMOUNT });
});
it('succeeds with no bridge calls and an input balance', async () => {
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls: [],
});
await callBridgeTransferFromAsync({
bridgeData,
sellAmount: new BigNumber(1),
});
});
it('succeeds if entire input token balance is not consumed', async () => {
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls: allBridgeCalls,
});
await callBridgeTransferFromAsync({
bridgeData,
sellAmount: totalFillableInputAmount.plus(1),
});
});
it('fails if not authorized', async () => {
const calls = goodBridgeCalls.slice(0, 1);
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
await callAndTransactAsync(testContract.setAuthorized(NULL_ADDRESS));
return expect(callBridgeTransferFromAsync({ bridgeData, sellAmount: new BigNumber(1) })).to.revertWith(
NOT_AUTHORIZED_REVERT,
);
});
it('succeeds with one bridge call', async () => {
const calls = goodBridgeCalls.slice(0, 1);
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
await callBridgeTransferFromAsync({ bridgeData, sellAmount: calls[0].inputTokenAmount });
});
it('succeeds with many bridge calls', async () => {
const calls = goodBridgeCalls;
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
await callBridgeTransferFromAsync({ bridgeData });
});
it('swallows a failing bridge call', async () => {
const calls = _.shuffle([...goodBridgeCalls, failingBridgeCall]);
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
await callBridgeTransferFromAsync({ bridgeData });
});
it('consumes input tokens for output tokens', async () => {
const calls = allBridgeCalls;
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
await callBridgeTransferFromAsync({ bridgeData });
const currentBridgeInputBalance = await testContract
.balanceOf(inputToken, testContract.address)
.callAsync();
expect(currentBridgeInputBalance).to.bignumber.eq(0);
const currentRecipientOutputBalance = await testContract
.balanceOf(outputToken, DEFAULTS.toAddress)
.callAsync();
expect(currentRecipientOutputBalance).to.bignumber.eq(totalFillableOutputAmount);
});
it("transfers only up to each call's input amount to each bridge", async () => {
const calls = goodBridgeCalls;
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
const logs = await callBridgeTransferFromAsync({ bridgeData });
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
for (const [call, btf] of shortZip(goodBridgeCalls, btfs)) {
expect(btf.inputTokenBalance).to.bignumber.eq(call.inputTokenAmount);
}
});
it('transfers only up to outstanding sell amount to each bridge', async () => {
// Prepend an extra bridge call.
const calls = [
await createBridgeCallAsync({
callFields: {
inputTokenAmount: new BigNumber(1),
outputTokenAmount: new BigNumber(1),
},
}),
...goodBridgeCalls,
];
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
const logs = await callBridgeTransferFromAsync({ bridgeData });
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
expect(btfs).to.be.length(goodBridgeCalls.length + 1);
// The last call will receive 1 less token.
const lastCall = calls.slice(-1)[0];
const lastBtf = btfs.slice(-1)[0];
expect(lastBtf.inputTokenBalance).to.bignumber.eq(lastCall.inputTokenAmount.minus(1));
});
it('recoups funds from a bridge that fails', async () => {
// Prepend a call that will take the whole input amount but will
// fail.
const badCall = await createBridgeCallAsync({
callFields: { inputTokenAmount: totalFillableInputAmount },
returnCode: BRIDGE_FAILURE,
});
const calls = [badCall, ...goodBridgeCalls];
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
const logs = await callBridgeTransferFromAsync({ bridgeData });
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
expect(btfs).to.be.length(goodBridgeCalls.length);
});
it('recoups funds from a bridge that reverts', async () => {
// Prepend a call that will take the whole input amount but will
// revert.
const badCall = await createBridgeCallAsync({
callFields: { inputTokenAmount: totalFillableInputAmount },
revertError: BRIDGE_REVERT_ERROR,
});
const calls = [badCall, ...goodBridgeCalls];
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
const logs = await callBridgeTransferFromAsync({ bridgeData });
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
expect(btfs).to.be.length(goodBridgeCalls.length);
});
it('recoups funds from a bridge that under-pays', async () => {
// Prepend a call that will take the whole input amount but will
// underpay the output amount..
const badCall = await createBridgeCallAsync({
callFields: {
inputTokenAmount: totalFillableInputAmount,
outputTokenAmount: new BigNumber(2),
},
outputFillAmount: new BigNumber(1),
});
const calls = [badCall, ...goodBridgeCalls];
const bridgeData = dexForwarderBridgeDataEncoder.encode({
inputToken,
calls,
});
const logs = await callBridgeTransferFromAsync({ bridgeData });
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
expect(btfs).to.be.length(goodBridgeCalls.length);
});
});
describe('executeBridgeCall()', () => {
it('cannot be called externally', async () => {
return expect(
testContract
.executeBridgeCall(
randomAddress(),
randomAddress(),
randomAddress(),
randomAddress(),
new BigNumber(1),
new BigNumber(1),
constants.NULL_BYTES,
)
.callAsync(),
).to.revertWith('DexForwarderBridge/ONLY_SELF');
});
});
});

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "1.1.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "1.1.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "1.1.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "1.1.24",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.1.27 - _April 1, 2021_
* Dependencies updated
## v1.1.26 - _March 17, 2021_
* Dependencies updated
## v1.1.25 - _February 24, 2021_
* Dependencies updated
## v1.1.24 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-broker",
"version": "1.1.24",
"version": "1.1.27",
"engines": {
"node": ">=6.12"
},
@@ -51,16 +51,16 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/sol-compiler": "^4.5.2",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-erc721": "^3.1.27",
"@0x/contracts-exchange": "^3.2.28",
"@0x/contracts-exchange-libs": "^4.3.27",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -81,11 +81,11 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/order-utils": "^10.4.16",
"@0x/order-utils": "^10.4.19",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",
"ethereum-types": "^3.4.0"

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "3.1.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "3.1.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "3.1.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "3.1.25",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.28 - _April 1, 2021_
* Dependencies updated
## v3.1.27 - _March 17, 2021_
* Dependencies updated
## v3.1.26 - _February 24, 2021_
* Dependencies updated
## v3.1.25 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-coordinator",
"version": "3.1.25",
"version": "3.1.28",
"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.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-dev-utils": "^1.3.26",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-gen": "^2.0.32",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/order-utils": "^10.4.19",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/web3-wrapper": "^7.4.1",
@@ -79,15 +79,15 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/assert": "^3.0.21",
"@0x/base-contract": "^6.2.18",
"@0x/contract-addresses": "^5.10.0",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/contract-addresses": "^6.0.0",
"@0x/contracts-exchange": "^3.2.28",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/json-schemas": "^5.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "1.3.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "1.3.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "1.3.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "1.3.23",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.3.26 - _April 1, 2021_
* Dependencies updated
## v1.3.25 - _March 17, 2021_
* Dependencies updated
## v1.3.24 - _February 24, 2021_
* Dependencies updated
## v1.3.23 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-dev-utils",
"version": "1.3.23",
"version": "1.3.26",
"engines": {
"node": ">=6.12"
},
@@ -41,13 +41,13 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/dev-utils",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/abi-gen": "^5.4.21",
"@0x/assert": "^3.0.21",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/sol-compiler": "^4.5.2",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -60,7 +60,7 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "2.1.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "2.1.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "2.1.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "2.1.24",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.1.27 - _April 1, 2021_
* Dependencies updated
## v2.1.26 - _March 17, 2021_
* Dependencies updated
## v2.1.25 - _February 24, 2021_
* Dependencies updated
## v2.1.24 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc1155",
"version": "2.1.24",
"version": "2.1.27",
"engines": {
"node": ">=6.12"
},
@@ -52,11 +52,11 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -77,11 +77,11 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/utils": "^6.2.0",
"@0x/web3-wrapper": "^7.4.1",
"lodash": "^4.17.11"

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "3.3.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "3.3.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "3.3.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "3.3.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.3.6 - _April 1, 2021_
* Dependencies updated
## v3.3.5 - _March 17, 2021_
* Dependencies updated
## v3.3.4 - _February 24, 2021_
* Dependencies updated
## v3.3.3 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "3.3.3",
"version": "3.3.6",
"engines": {
"node": ">=6.12"
},
@@ -51,12 +51,12 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -79,7 +79,7 @@
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18"

View File

@@ -6,6 +6,7 @@ export {
WETH9Events,
WETH9DepositEventArgs,
WETH9TransferEventArgs,
WETH9WithdrawalEventArgs,
ZRXTokenContract,
DummyERC20TokenTransferEventArgs,
ERC20TokenEventArgs,

View File

@@ -39,8 +39,8 @@ describe('EtherToken', () => {
artifacts.WETH9,
provider,
{
gasPrice,
...txDefaults,
gasPrice,
},
artifacts,
);

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "3.1.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "3.1.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "3.1.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "3.1.24",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.27 - _April 1, 2021_
* Dependencies updated
## v3.1.26 - _March 17, 2021_
* Dependencies updated
## v3.1.25 - _February 24, 2021_
* Dependencies updated
## v3.1.24 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc721",
"version": "3.1.24",
"version": "3.1.27",
"engines": {
"node": ">=6.12"
},
@@ -52,12 +52,12 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -81,7 +81,7 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18"

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "4.2.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "4.2.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "4.2.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "4.2.25",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.2.28 - _April 1, 2021_
* Dependencies updated
## v4.2.27 - _March 17, 2021_
* Dependencies updated
## v4.2.26 - _February 24, 2021_
* Dependencies updated
## v4.2.25 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-forwarder",
"version": "4.2.25",
"version": "4.2.28",
"engines": {
"node": ">=6.12"
},
@@ -52,20 +52,20 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-dev-utils": "^1.3.26",
"@0x/contracts-erc1155": "^2.1.27",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-erc721": "^3.1.27",
"@0x/contracts-exchange": "^3.2.28",
"@0x/contracts-exchange-libs": "^4.3.27",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/order-utils": "^10.4.19",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -87,7 +87,7 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "4.3.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "4.3.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "4.3.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "4.3.24",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.3.27 - _April 1, 2021_
* Dependencies updated
## v4.3.26 - _March 17, 2021_
* Dependencies updated
## v4.3.25 - _February 24, 2021_
* Dependencies updated
## v4.3.24 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-libs",
"version": "4.3.24",
"version": "4.3.27",
"engines": {
"node": ">=6.12"
},
@@ -52,10 +52,10 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/libs",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-gen": "^2.0.32",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/subproviders": "^6.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -77,13 +77,13 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/order-utils": "^10.4.16",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/order-utils": "^10.4.19",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "3.2.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "3.2.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "3.2.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "3.2.25",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.28 - _April 1, 2021_
* Dependencies updated
## v3.2.27 - _March 17, 2021_
* Dependencies updated
## v3.2.26 - _February 24, 2021_
* Dependencies updated
## v3.2.25 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange",
"version": "3.2.25",
"version": "3.2.28",
"engines": {
"node": ">=6.12"
},
@@ -52,16 +52,16 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-multisig": "^4.1.25",
"@0x/contracts-staking": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-exchange-libs": "^4.3.27",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-multisig": "^4.1.28",
"@0x/contracts-staking": "^2.0.35",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -85,15 +85,15 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/order-utils": "^10.4.16",
"@0x/contracts-dev-utils": "^1.3.26",
"@0x/contracts-erc1155": "^2.1.27",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-erc721": "^3.1.27",
"@0x/order-utils": "^10.4.19",
"@0x/utils": "^6.2.0",
"lodash": "^4.17.11"
},

View File

@@ -12,12 +12,12 @@ export abstract class AbstractBalanceAndProxyAllowanceFetcher {
* @param userAddress Ethereum address for which to fetch the balance
* @return Balance amount in base units
*/
public abstract async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
public abstract getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
/**
* Get the 0x asset proxy allowance of assetData for userAddress
* @param assetData AssetData for which to fetch the allowance
* @param userAddress Ethereum address for which to fetch the allowance
* @return Allowance amount in base units
*/
public abstract async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
public abstract getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
}

View File

@@ -1,8 +1,8 @@
import { BigNumber } from '@0x/utils';
export abstract class AbstractBalanceAndProxyAllowanceLazyStore {
public abstract async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
public abstract async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
public abstract getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
public abstract getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
public abstract setBalance(assetData: string, userAddress: string, balance: BigNumber): void;
public abstract deleteBalance(assetData: string, userAddress: string): void;
public abstract setProxyAllowance(assetData: string, userAddress: string, proxyAllowance: BigNumber): void;

View File

@@ -11,5 +11,5 @@ export abstract class AbstractOrderFilledCancelledFetcher {
* @param orderHash OrderHash of order we are interested in
* @return FilledTakerAmount
*/
public abstract async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
public abstract getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
}

View File

@@ -1,7 +1,7 @@
import { BigNumber } from '@0x/utils';
export abstract class AbstractOrderFilledCancelledLazyStore {
public abstract async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
public abstract getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
public abstract setFilledTakerAmount(orderHash: string, balance: BigNumber): void;
public abstract deleteFilledTakerAmount(orderHash: string): void;
public abstract setIsCancelled(orderHash: string, isCancelled: boolean): void;

View File

@@ -18,6 +18,7 @@ import {
IsolatedExchangeFillEventArgs as FillEventArgs,
} from '../wrappers';
export { Order } from '@0x/types';
export interface AssetBalances {
[assetData: string]: { [address: string]: BigNumber };
}
@@ -27,7 +28,6 @@ export interface IsolatedExchangeEvents {
transferFromCalls: DispatchTransferFromCallArgs[];
}
export type Order = Order;
export type Numberish = string | number | BigNumber;
export const DEFAULT_GOOD_SIGNATURE = createGoodSignature();

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "6.2.22",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "6.2.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "6.2.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "6.2.19",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v6.2.22 - _April 1, 2021_
* Dependencies updated
## v6.2.21 - _March 17, 2021_
* Dependencies updated
## v6.2.20 - _February 24, 2021_
* Dependencies updated
## v6.2.19 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-extensions",
"version": "6.2.19",
"version": "6.2.22",
"engines": {
"node": ">=6.12"
},
@@ -52,18 +52,18 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-dev-utils": "^1.3.26",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-erc721": "^3.1.27",
"@0x/contracts-exchange": "^3.2.28",
"@0x/contracts-exchange-libs": "^4.3.27",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/order-utils": "^10.4.19",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -87,11 +87,11 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/typescript-typings": "^5.1.6",
"ethereum-types": "^3.4.0"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-integrations",
"version": "2.7.26",
"version": "2.7.30",
"private": true,
"engines": {
"node": ">=6.12"
@@ -52,23 +52,23 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contract-addresses": "^5.10.0",
"@0x/contract-wrappers": "^13.12.3",
"@0x/contracts-broker": "^1.1.24",
"@0x/contracts-coordinator": "^3.1.25",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-exchange-forwarder": "^4.2.25",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-extensions": "^6.2.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contract-addresses": "^6.0.0",
"@0x/contract-wrappers": "^13.15.0",
"@0x/contracts-broker": "^1.1.27",
"@0x/contracts-coordinator": "^3.1.28",
"@0x/contracts-dev-utils": "^1.3.26",
"@0x/contracts-exchange-forwarder": "^4.2.28",
"@0x/contracts-exchange-libs": "^4.3.27",
"@0x/contracts-extensions": "^6.2.22",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-utils": "^4.7.6",
"@0x/coordinator-server": "^1.0.5",
"@0x/dev-utils": "^4.2.1",
"@0x/migrations": "^6.6.0",
"@0x/order-utils": "^10.4.16",
"@0x/protocol-utils": "^1.2.0",
"@0x/sol-compiler": "^4.5.2",
"@0x/migrations": "^8.0.0",
"@0x/order-utils": "^10.4.19",
"@0x/protocol-utils": "^1.4.0",
"@0x/sol-compiler": "^4.6.1",
"@0x/tslint-config": "^4.1.3",
"@0x/web3-wrapper": "^7.4.1",
"@azure/core-asynciterator-polyfill": "^1.0.0",
@@ -90,20 +90,20 @@
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/asset-swapper": "^6.0.0",
"@0x/asset-swapper": "^6.4.0",
"@0x/base-contract": "^6.2.18",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc1155": "^2.1.24",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-erc721": "^3.1.24",
"@0x/contracts-exchange": "^3.2.25",
"@0x/contracts-multisig": "^4.1.25",
"@0x/contracts-staking": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-zero-ex": "^0.18.2",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-erc1155": "^2.1.27",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-erc721": "^3.1.27",
"@0x/contracts-exchange": "^3.2.28",
"@0x/contracts-multisig": "^4.1.28",
"@0x/contracts-staking": "^2.0.35",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-zero-ex": "^0.21.0",
"@0x/subproviders": "^6.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -63,11 +63,9 @@ blockchainTests.fork('DevUtils dydx order validation tests', env => {
let dai: ERC20TokenContract;
let usdc: ERC20TokenContract;
let devUtils: DevUtilsContract;
let accountOwner: string;
let minMarginRatio: number;
before(async () => {
[accountOwner] = await env.getAccountAddressesAsync();
dydx = new IDydxContract(DYDX_ADDRESS, env.provider, env.txDefaults);
dai = new ERC20TokenContract(DAI_ADDRESS, env.provider, env.txDefaults);
usdc = new ERC20TokenContract(USDC_ADDRESS, env.provider, env.txDefaults);

View File

@@ -19,5 +19,5 @@ export function filterActorsByRole<TClass extends Constructor>(
actors: Actor[],
role: TClass,
): Array<InstanceType<typeof role>> {
return actors.filter(actor => actor.mixins.includes(role.name)) as InstanceType<typeof role>;
return actors.filter(actor => actor.mixins.includes(role.name)) as Array<InstanceType<typeof role>>;
}

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "4.1.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "4.1.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "4.1.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "4.1.25",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.1.28 - _April 1, 2021_
* Dependencies updated
## v4.1.27 - _March 17, 2021_
* Dependencies updated
## v4.1.26 - _February 24, 2021_
* Dependencies updated
## v4.1.25 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-multisig",
"version": "4.1.25",
"version": "4.1.28",
"engines": {
"node": ">=6.12"
},
@@ -49,14 +49,14 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
"@0x/utils": "^6.2.0",
@@ -75,7 +75,7 @@
"shx": "^0.2.2",
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "2.0.35",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "2.0.34",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "2.0.33",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "2.0.32",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.35 - _April 1, 2021_
* Dependencies updated
## v2.0.34 - _March 17, 2021_
* Dependencies updated
## v2.0.33 - _February 24, 2021_
* Dependencies updated
## v2.0.32 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-staking",
"version": "2.0.32",
"version": "2.0.35",
"engines": {
"node": ">=6.12"
},
@@ -53,16 +53,16 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-dev-utils": "^1.3.23",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-exchange-libs": "^4.3.24",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-utils": "^4.7.3",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-dev-utils": "^1.3.26",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-exchange-libs": "^4.3.27",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-utils": "^4.7.6",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/order-utils": "^10.4.19",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
@@ -84,11 +84,11 @@
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.2.0",
"ethereum-types": "^3.4.0",

View File

@@ -4,6 +4,7 @@ import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types';
import { constants as stakingConstants } from './constants';
export { Numberish } from '@0x/contracts-test-utils';
// tslint:disable:max-classes-per-file
export interface StakingParams {
@@ -259,5 +260,3 @@ export class AggregatedStats {
export interface AggregatedStatsByEpoch {
[epoch: string]: AggregatedStats;
}
export type Numberish = Numberish;

View File

@@ -12,7 +12,6 @@ import {
blockchainTests.resets('Exchange Unit Tests', env => {
// Addresses
let nonOwner: string;
let owner: string;
let nonExchange: string;
let exchange: string;
@@ -24,7 +23,7 @@ blockchainTests.resets('Exchange Unit Tests', env => {
before(async () => {
// Set up addresses for testing.
[nonOwner, owner, nonExchange, exchange, nonAuthority, authority] = await env.getAccountAddressesAsync();
[, owner, nonExchange, exchange, nonAuthority, authority] = await env.getAccountAddressesAsync();
// Deploy the Exchange Manager contract.
exchangeManager = await TestExchangeManagerContract.deployFrom0xArtifactAsync(

View File

@@ -543,7 +543,7 @@ blockchainTests.resets('Finalizer unit tests', env => {
const expectedPoolRewards = await calculatePoolRewardsAsync(INITIAL_BALANCE, pools);
const [pool, reward] = _.sampleSize(shortZip(pools, expectedPoolRewards), 1)[0];
return assertUnfinalizedPoolRewardsAsync(pool.poolId, {
totalReward: (reward as any) as BigNumber,
totalReward: reward,
membersStake: pool.membersStake,
});
});

View File

@@ -12,17 +12,13 @@ import * as _ from 'lodash';
import { artifacts } from '../artifacts';
import { TestCobbDouglasContract } from '../wrappers';
// tslint:disable: no-unnecessary-type-assertion
blockchainTests('LibCobbDouglas unit tests', env => {
const FUZZ_COUNT = 1024;
const PRECISION = 15;
let testContract: TestCobbDouglasContract;
let ownerAddress: string;
let notOwnerAddress: string;
before(async () => {
[ownerAddress, notOwnerAddress] = await env.getAccountAddressesAsync();
testContract = await TestCobbDouglasContract.deployFrom0xArtifactAsync(
artifacts.TestCobbDouglas,
env.provider,
@@ -211,4 +207,3 @@ blockchainTests('LibCobbDouglas unit tests', env => {
});
});
});
// tslint:enable:no-unnecessary-type-assertion

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "5.3.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "5.3.23",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "5.3.22",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "5.3.21",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.3.24 - _April 1, 2021_
* Dependencies updated
## v5.3.23 - _March 17, 2021_
* Dependencies updated
## v5.3.22 - _February 24, 2021_
* Dependencies updated
## v5.3.21 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-test-utils",
"version": "5.3.21",
"version": "5.3.24",
"engines": {
"node": ">=6.12"
},
@@ -34,23 +34,23 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/test-utils",
"devDependencies": {
"@0x/sol-compiler": "^4.5.2",
"@0x/sol-compiler": "^4.6.1",
"@0x/tslint-config": "^4.1.3",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/assert": "^3.0.21",
"@0x/base-contract": "^6.2.18",
"@0x/contract-addresses": "^5.10.0",
"@0x/contract-addresses": "^6.0.0",
"@0x/dev-utils": "^4.2.1",
"@0x/json-schemas": "^5.4.1",
"@0x/order-utils": "^10.4.16",
"@0x/sol-coverage": "^4.0.29",
"@0x/sol-profiler": "^4.1.19",
"@0x/sol-trace": "^3.0.29",
"@0x/order-utils": "^10.4.19",
"@0x/sol-coverage": "^4.0.31",
"@0x/sol-profiler": "^4.1.21",
"@0x/sol-trace": "^3.0.31",
"@0x/subproviders": "^6.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -14,6 +14,6 @@ export function shortZip<T1, T2>(a: T1[], b: T2[]): Array<[T1, T2]> {
export function replaceKeysDeep(obj: {}, mapKeys: (key: string) => string | void): _.Dictionary<{}> {
return _.transform(obj, (result, value, key) => {
const currentKey = mapKeys(key) || key;
result[currentKey] = _.isObject(value) ? replaceKeysDeep(value, mapKeys) : value;
result[currentKey] = _.isObject(value) ? replaceKeysDeep(value as {}, mapKeys) : (value as {});
});
}

View File

@@ -22,14 +22,14 @@ export class OrderFactory {
): Promise<SignedOrder> {
const fifteenMinutesInSeconds = 15 * 60;
const currentBlockTimestamp = await getLatestBlockTimestampAsync();
const order = ({
const order = {
takerAddress: constants.NULL_ADDRESS,
senderAddress: constants.NULL_ADDRESS,
expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(fifteenMinutesInSeconds),
salt: generatePseudoRandomSalt(),
...this._defaultOrderParams,
...customOrderParams,
} as any) as Order;
} as Order; // tslint:disable-line:no-object-literal-type-assertion
const orderHashBuff = orderHashUtils.getOrderHashBuffer(order);
const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType);
const signedOrder = {

View File

@@ -30,7 +30,8 @@ export const orderUtils = {
return cancel;
},
createOrderWithoutSignature(signedOrder: SignedOrder): Order {
return _.omit(signedOrder, ['signature']) as Order;
const { signature, ...order } = signedOrder;
return order;
},
createBatchMatchOrders(signedOrdersLeft: SignedOrder[], signedOrdersRight: SignedOrder[]): BatchMatchOrder {
return {

View File

@@ -1,4 +1,32 @@
[
{
"timestamp": 1617311315,
"version": "1.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.1.0",
"changes": [
{
"note": "Make the proposal/quorum thresholds updatable",
"pr": 165
}
],
"timestamp": 1616005394
},
{
"timestamp": 1614141718,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "1.0.1",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.1.1 - _April 1, 2021_
* Dependencies updated
## v1.1.0 - _March 17, 2021_
* Make the proposal/quorum thresholds updatable (#165)
## v1.0.2 - _February 24, 2021_
* Dependencies updated
## v1.0.1 - _February 10, 2021_
* Dependencies updated

View File

@@ -96,6 +96,18 @@ interface IZrxTreasury {
view
returns (uint256);
/// @dev Updates the proposal and quorum thresholds to the given
/// values. Note that this function is only callable by the
/// treasury contract itself, so the threshold can only be
/// updated via a successful treasury proposal.
/// @param newProposalThreshold The new value for the proposal threshold.
/// @param newQuorumThreshold The new value for the quorum threshold.
function updateThresholds(
uint256 newProposalThreshold,
uint256 newQuorumThreshold
)
external;
/// @dev Creates a proposal to send ZRX from this treasury on the
/// the given actions. Must have at least `proposalThreshold`
/// of voting power to call this function. See `getVotingPower`

View File

@@ -42,8 +42,8 @@ contract ZrxTreasury is
DefaultPoolOperator public immutable override defaultPoolOperator;
bytes32 public immutable override defaultPoolId;
uint256 public immutable override votingPeriod;
uint256 public immutable override proposalThreshold;
uint256 public immutable override quorumThreshold;
uint256 public override proposalThreshold;
uint256 public override quorumThreshold;
// Storage
Proposal[] public proposals;
@@ -82,6 +82,24 @@ contract ZrxTreasury is
receive() external payable {}
// solhint-enable
/// @dev Updates the proposal and quorum thresholds to the given
/// values. Note that this function is only callable by the
/// treasury contract itself, so the threshold can only be
/// updated via a successful treasury proposal.
/// @param newProposalThreshold The new value for the proposal threshold.
/// @param newQuorumThreshold The new value for the quorum threshold.
function updateThresholds(
uint256 newProposalThreshold,
uint256 newQuorumThreshold
)
external
override
{
require(msg.sender == address(this), "updateThresholds/ONLY_SELF");
proposalThreshold = newProposalThreshold;
quorumThreshold = newQuorumThreshold;
}
/// @dev Creates a proposal to send ZRX from this treasury on the
/// the given actions. Must have at least `proposalThreshold`
/// of voting power to call this function. See `getVotingPower`

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-treasury",
"version": "1.0.1",
"version": "1.1.1",
"engines": {
"node": ">=6.12"
},
@@ -46,14 +46,14 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contract-addresses": "^5.10.0",
"@0x/contracts-asset-proxy": "^3.7.6",
"@0x/contracts-erc20": "^3.3.3",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-staking": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/sol-compiler": "^4.4.1",
"@0x/abi-gen": "^5.4.21",
"@0x/contract-addresses": "^6.0.0",
"@0x/contracts-asset-proxy": "^3.7.9",
"@0x/contracts-erc20": "^3.3.6",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-staking": "^2.0.35",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/sol-compiler": "^4.6.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@types/isomorphic-fetch": "^0.0.35",
@@ -69,16 +69,16 @@
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/protocol-utils": "^1.2.0",
"@0x/subproviders": "^6.2.3",
"@0x/base-contract": "^6.2.18",
"@0x/protocol-utils": "^1.4.0",
"@0x/subproviders": "^6.4.1",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.1.1",
"@0x/web3-wrapper": "^7.3.0",
"@0x/utils": "^6.2.0",
"@0x/web3-wrapper": "^7.4.1",
"ethereum-types": "^3.4.0",
"ethereumjs-util": "^5.1.1"
},

View File

@@ -580,4 +580,47 @@ blockchainTests.resets('Treasury governance', env => {
expect(await weth.balanceOf(staking.address).callAsync()).to.bignumber.equal(wethAmount);
});
});
describe('Can update thresholds via proposal', () => {
it('Updates proposal and quorum thresholds', async () => {
// Delegator has enough ZRX to create and pass a proposal
await staking.stake(TREASURY_PARAMS.quorumThreshold).awaitTransactionSuccessAsync({ from: delegator });
await staking
.moveStake(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, defaultPoolId),
TREASURY_PARAMS.quorumThreshold,
)
.awaitTransactionSuccessAsync({ from: delegator });
await fastForwardToNextEpochAsync();
const currentEpoch = await staking.currentEpoch().callAsync();
const newProposalThreshold = new BigNumber(420);
const newQuorumThreshold = new BigNumber(1337);
const updateThresholdsAction = {
target: treasury.address,
data: treasury
.updateThresholds(newProposalThreshold, newQuorumThreshold)
.getABIEncodedTransactionData(),
value: constants.ZERO_AMOUNT,
};
const tx = treasury.propose(
[updateThresholdsAction],
currentEpoch.plus(3),
`Updates proposal threshold to ${newProposalThreshold} and quorum threshold to ${newQuorumThreshold}`,
[],
);
const proposalId = await tx.callAsync({ from: delegator });
await tx.awaitTransactionSuccessAsync({ from: delegator });
await fastForwardToNextEpochAsync();
await fastForwardToNextEpochAsync();
await treasury.castVote(proposalId, true, []).awaitTransactionSuccessAsync({ from: delegator });
await fastForwardToNextEpochAsync();
await treasury
.execute(proposalId, [updateThresholdsAction])
.awaitTransactionSuccessAsync({ from: delegator });
const proposalThreshold = await treasury.proposalThreshold().callAsync();
const quorumThreshold = await treasury.quorumThreshold().callAsync();
expect(proposalThreshold).to.bignumber.equal(newProposalThreshold);
expect(quorumThreshold).to.bignumber.equal(newQuorumThreshold);
});
});
});

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1617311315,
"version": "4.7.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "4.7.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "4.7.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "4.7.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.7.6 - _April 1, 2021_
* Dependencies updated
## v4.7.5 - _March 17, 2021_
* Dependencies updated
## v4.7.4 - _February 24, 2021_
* Dependencies updated
## v4.7.3 - _February 10, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-utils",
"version": "4.7.3",
"version": "4.7.6",
"engines": {
"node": ">=6.12"
},
@@ -50,12 +50,12 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/utils",
"devDependencies": {
"@0x/abi-gen": "^5.4.19",
"@0x/contracts-gen": "^2.0.30",
"@0x/contracts-test-utils": "^5.3.21",
"@0x/abi-gen": "^5.4.21",
"@0x/contracts-gen": "^2.0.32",
"@0x/contracts-test-utils": "^5.3.24",
"@0x/dev-utils": "^4.2.1",
"@0x/order-utils": "^10.4.16",
"@0x/sol-compiler": "^4.5.2",
"@0x/order-utils": "^10.4.19",
"@0x/sol-compiler": "^4.6.1",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",
"@0x/web3-wrapper": "^7.4.1",
@@ -76,7 +76,7 @@
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typescript": "3.0.1"
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.2.18",

View File

@@ -1,4 +1,86 @@
[
{
"version": "0.21.0",
"changes": [
{
"note": "Encoding protocol ID and source name in bridge source ID",
"pr": 162
},
{
"note": "Add PancakeSwapFeature",
"pr": 164
},
{
"note": "Remove TokenSpender/AllowanceTarget/greedy tokens stuff",
"pr": 164
},
{
"note": "Added Nerve in BridgeAdapter",
"pr": 181
},
{
"note": "Delete TokenSpenderFeature",
"pr": 189
},
{
"note": "Fix PancakeSwapFeature BakerySwap swap selector",
"pr": 190
}
],
"timestamp": 1617311315
},
{
"version": "0.20.0",
"changes": [
{
"note": "Add `MooniswapLiquidityProvider`",
"pr": 143
},
{
"note": "Emit `LiquidityProviderFill` event in `CurveLiquidityProvider`",
"pr": 143
},
{
"note": "Add BatchFillNativeOrdersFeature and MultiplexFeature",
"pr": 140
},
{
"note": "Export MultiplexFeatureContract",
"pr": 168
}
],
"timestamp": 1616005394
},
{
"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": [

View File

@@ -5,6 +5,31 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v0.21.0 - _April 1, 2021_
* Encoding protocol ID and source name in bridge source ID (#162)
* Add PancakeSwapFeature (#164)
* Remove TokenSpender/AllowanceTarget/greedy tokens stuff (#164)
* Added Nerve in BridgeAdapter (#181)
* Delete TokenSpenderFeature (#189)
* Fix PancakeSwapFeature BakerySwap swap selector (#190)
## v0.20.0 - _March 17, 2021_
* Add `MooniswapLiquidityProvider` (#143)
* Emit `LiquidityProviderFill` event in `CurveLiquidityProvider` (#143)
* Add BatchFillNativeOrdersFeature and MultiplexFeature (#140)
* Export MultiplexFeatureContract (#168)
## 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)

View File

@@ -20,26 +20,31 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "./features/IOwnableFeature.sol";
import "./features/ISimpleFunctionRegistryFeature.sol";
import "./features/ITokenSpenderFeature.sol";
import "./features/ITransformERC20Feature.sol";
import "./features/IMetaTransactionsFeature.sol";
import "./features/IUniswapFeature.sol";
import "./features/ILiquidityProviderFeature.sol";
import "./features/INativeOrdersFeature.sol";
import "./features/interfaces/IOwnableFeature.sol";
import "./features/interfaces/ISimpleFunctionRegistryFeature.sol";
import "./features/interfaces/ITokenSpenderFeature.sol";
import "./features/interfaces/ITransformERC20Feature.sol";
import "./features/interfaces/IMetaTransactionsFeature.sol";
import "./features/interfaces/IUniswapFeature.sol";
import "./features/interfaces/IPancakeSwapFeature.sol";
import "./features/interfaces/ILiquidityProviderFeature.sol";
import "./features/interfaces/INativeOrdersFeature.sol";
import "./features/interfaces/IBatchFillNativeOrdersFeature.sol";
import "./features/interfaces/IMultiplexFeature.sol";
/// @dev Interface for a fully featured Exchange Proxy.
interface IZeroEx is
IOwnableFeature,
ISimpleFunctionRegistryFeature,
ITokenSpenderFeature,
ITransformERC20Feature,
IMetaTransactionsFeature,
IUniswapFeature,
IPancakeSwapFeature,
ILiquidityProviderFeature,
INativeOrdersFeature
INativeOrdersFeature,
IBatchFillNativeOrdersFeature,
IMultiplexFeature
{
// solhint-disable state-visibility

View File

@@ -170,4 +170,21 @@ library LibNativeOrdersRichErrors {
maker
);
}
function BatchFillIncompleteError(
bytes32 orderHash,
uint256 takerTokenFilledAmount,
uint256 takerTokenFillAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("BatchFillIncompleteError(bytes32,uint256,uint256)")),
orderHash,
takerTokenFilledAmount,
takerTokenFillAmount
);
}
}

View File

@@ -1,56 +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;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/AuthorizableV06.sol";
import "../errors/LibSpenderRichErrors.sol";
import "./IAllowanceTarget.sol";
/// @dev The allowance target for the TokenSpender feature.
contract AllowanceTarget is
IAllowanceTarget,
AuthorizableV06
{
// solhint-disable no-unused-vars,indent,no-empty-blocks
using LibRichErrorsV06 for bytes;
/// @dev Execute an arbitrary call. Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @return resultData The data returned by the call.
function executeCall(
address payable target,
bytes calldata callData
)
external
override
onlyAuthorized
returns (bytes memory resultData)
{
bool success;
(success, resultData) = target.call(callData);
if (!success) {
resultData.rrevert();
}
}
}

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

@@ -0,0 +1,198 @@
// 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-utils/contracts/src/v06/LibMathV06.sol";
import "../errors/LibNativeOrdersRichErrors.sol";
import "../fixins/FixinCommon.sol";
import "../fixins/FixinEIP712.sol";
import "../migrations/LibMigrate.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IBatchFillNativeOrdersFeature.sol";
import "./interfaces/INativeOrdersFeature.sol";
import "./libs/LibNativeOrder.sol";
import "./libs/LibSignature.sol";
/// @dev Feature for batch/market filling limit and RFQ orders.
contract BatchFillNativeOrdersFeature is
IFeature,
IBatchFillNativeOrdersFeature,
FixinCommon,
FixinEIP712
{
using LibSafeMathV06 for uint128;
using LibSafeMathV06 for uint256;
using LibRichErrorsV06 for bytes;
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "BatchFill";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
constructor(address zeroExAddress)
public
FixinEIP712(zeroExAddress)
{
// solhint-disable no-empty-blocks
}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
/// @return success `LibMigrate.SUCCESS` on success.
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.batchFillLimitOrders.selector);
_registerFeatureFunction(this.batchFillRfqOrders.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Fills multiple limit orders.
/// @param orders Array of limit orders.
/// @param signatures Array of signatures corresponding to each order.
/// @param takerTokenFillAmounts Array of desired amounts to fill each order.
/// @param revertIfIncomplete If true, reverts if this function fails to
/// fill the full fill amount for any individual order.
/// @return takerTokenFilledAmounts Array of amounts filled, in taker token.
/// @return makerTokenFilledAmounts Array of amounts filled, in maker token.
function batchFillLimitOrders(
LibNativeOrder.LimitOrder[] calldata orders,
LibSignature.Signature[] calldata signatures,
uint128[] calldata takerTokenFillAmounts,
bool revertIfIncomplete
)
external
payable
override
returns (
uint128[] memory takerTokenFilledAmounts,
uint128[] memory makerTokenFilledAmounts
)
{
require(
orders.length == signatures.length && orders.length == takerTokenFillAmounts.length,
'BatchFillNativeOrdersFeature::batchFillLimitOrders/MISMATCHED_ARRAY_LENGTHS'
);
takerTokenFilledAmounts = new uint128[](orders.length);
makerTokenFilledAmounts = new uint128[](orders.length);
uint256 protocolFee = uint256(INativeOrdersFeature(address(this)).getProtocolFeeMultiplier())
.safeMul(tx.gasprice);
uint256 ethProtocolFeePaid;
for (uint256 i = 0; i != orders.length; i++) {
try
INativeOrdersFeature(address(this))._fillLimitOrder
(
orders[i],
signatures[i],
takerTokenFillAmounts[i],
msg.sender,
msg.sender
)
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
// Update amounts filled.
(takerTokenFilledAmounts[i], makerTokenFilledAmounts[i]) =
(takerTokenFilledAmount, makerTokenFilledAmount);
ethProtocolFeePaid = ethProtocolFeePaid.safeAdd(protocolFee);
} catch {}
if (
revertIfIncomplete &&
takerTokenFilledAmounts[i] < takerTokenFillAmounts[i]
) {
bytes32 orderHash = _getEIP712Hash(
LibNativeOrder.getLimitOrderStructHash(orders[i])
);
// Did not fill the amount requested.
LibNativeOrdersRichErrors.BatchFillIncompleteError(
orderHash,
takerTokenFilledAmounts[i],
takerTokenFillAmounts[i]
).rrevert();
}
}
LibNativeOrder.refundExcessProtocolFeeToSender(ethProtocolFeePaid);
}
/// @dev Fills multiple RFQ orders.
/// @param orders Array of RFQ orders.
/// @param signatures Array of signatures corresponding to each order.
/// @param takerTokenFillAmounts Array of desired amounts to fill each order.
/// @param revertIfIncomplete If true, reverts if this function fails to
/// fill the full fill amount for any individual order.
/// @return takerTokenFilledAmounts Array of amounts filled, in taker token.
/// @return makerTokenFilledAmounts Array of amounts filled, in maker token.
function batchFillRfqOrders(
LibNativeOrder.RfqOrder[] calldata orders,
LibSignature.Signature[] calldata signatures,
uint128[] calldata takerTokenFillAmounts,
bool revertIfIncomplete
)
external
override
returns (
uint128[] memory takerTokenFilledAmounts,
uint128[] memory makerTokenFilledAmounts
)
{
require(
orders.length == signatures.length && orders.length == takerTokenFillAmounts.length,
'BatchFillNativeOrdersFeature::batchFillRfqOrders/MISMATCHED_ARRAY_LENGTHS'
);
takerTokenFilledAmounts = new uint128[](orders.length);
makerTokenFilledAmounts = new uint128[](orders.length);
for (uint256 i = 0; i != orders.length; i++) {
try
INativeOrdersFeature(address(this))._fillRfqOrder
(
orders[i],
signatures[i],
takerTokenFillAmounts[i],
msg.sender
)
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
// Update amounts filled.
(takerTokenFilledAmounts[i], makerTokenFilledAmounts[i]) =
(takerTokenFilledAmount, makerTokenFilledAmount);
} catch {}
if (
revertIfIncomplete &&
takerTokenFilledAmounts[i] < takerTokenFillAmounts[i]
) {
// Did not fill the amount requested.
bytes32 orderHash = _getEIP712Hash(
LibNativeOrder.getRfqOrderStructHash(orders[i])
);
LibNativeOrdersRichErrors.BatchFillIncompleteError(
orderHash,
takerTokenFilledAmounts[i],
takerTokenFillAmounts[i]
).rrevert();
}
}
}
}

View File

@@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "../migrations/LibBootstrap.sol";
import "../storage/LibProxyStorage.sol";
import "./IBootstrapFeature.sol";
import "./interfaces/IBootstrapFeature.sol";
/// @dev Detachable `bootstrap()` feature.

View File

@@ -23,14 +23,16 @@ 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 "./IFeature.sol";
import "./ILiquidityProviderFeature.sol";
import "../transformers/LibERC20Transformer.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/ILiquidityProviderFeature.sol";
contract LiquidityProviderFeature is
@@ -45,27 +47,14 @@ 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, 4);
/// @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)
constructor(LiquidityProviderSandbox sandbox_)
public
FixinCommon()
FixinTokenSpender(greedyTokensBloomFilter)
{
sandbox = sandbox_;
}
@@ -95,9 +84,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 +103,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 +126,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 +137,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 +146,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

@@ -30,11 +30,11 @@ import "../fixins/FixinTokenSpender.sol";
import "../fixins/FixinEIP712.sol";
import "../migrations/LibMigrate.sol";
import "../storage/LibMetaTransactionsStorage.sol";
import "./IMetaTransactionsFeature.sol";
import "./ITransformERC20Feature.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IMetaTransactionsFeature.sol";
import "./interfaces/INativeOrdersFeature.sol";
import "./interfaces/ITransformERC20Feature.sol";
import "./libs/LibSignature.sol";
import "./IFeature.sol";
import "./INativeOrdersFeature.sol";
/// @dev MetaTransactions feature.
contract MetaTransactionsFeature is
@@ -78,7 +78,7 @@ contract MetaTransactionsFeature is
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "MetaTransactions";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 1);
/// @dev EIP712 typehash of the `MetaTransactionData` struct.
bytes32 public immutable MTX_EIP712_TYPEHASH = keccak256(
"MetaTransactionData("
@@ -105,11 +105,10 @@ contract MetaTransactionsFeature is
}
}
constructor(address zeroExAddress, bytes32 greedyTokensBloomFilter)
constructor(address zeroExAddress)
public
FixinCommon()
FixinEIP712(zeroExAddress)
FixinTokenSpender(greedyTokensBloomFilter)
{
// solhint-disable-next-line no-empty-blocks
}

View File

@@ -0,0 +1,803 @@
// 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 "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../external/ILiquidityProviderSandbox.sol";
import "../fixins/FixinCommon.sol";
import "../fixins/FixinEIP712.sol";
import "../fixins/FixinTokenSpender.sol";
import "../migrations/LibMigrate.sol";
import "../transformers/LibERC20Transformer.sol";
import "../vendor/ILiquidityProvider.sol";
import "../vendor/IUniswapV2Pair.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IMultiplexFeature.sol";
import "./interfaces/INativeOrdersFeature.sol";
import "./interfaces/ITransformERC20Feature.sol";
import "./libs/LibNativeOrder.sol";
/// @dev This feature enables efficient batch and multi-hop trades
/// using different liquidity sources.
contract MultiplexFeature is
IFeature,
IMultiplexFeature,
FixinCommon,
FixinEIP712,
FixinTokenSpender
{
using LibERC20Transformer for IERC20TokenV06;
using LibSafeMathV06 for uint128;
using LibSafeMathV06 for uint256;
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "MultiplexFeature";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 1);
/// @dev The WETH token contract.
IEtherTokenV06 private immutable weth;
/// @dev The sandbox contract address.
ILiquidityProviderSandbox public immutable sandbox;
// address of the UniswapV2Factory contract.
address private constant UNISWAP_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
// address of the (Sushiswap) UniswapV2Factory contract.
address private constant SUSHISWAP_FACTORY = 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac;
// Init code hash of the UniswapV2Pair contract.
uint256 private constant UNISWAP_PAIR_INIT_CODE_HASH = 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f;
// Init code hash of the (Sushiswap) UniswapV2Pair contract.
uint256 private constant SUSHISWAP_PAIR_INIT_CODE_HASH = 0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303;
constructor(
address zeroExAddress,
IEtherTokenV06 weth_,
ILiquidityProviderSandbox sandbox_
)
public
FixinEIP712(zeroExAddress)
{
weth = weth_;
sandbox = sandbox_;
}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
/// @return success `LibMigrate.SUCCESS` on success.
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.batchFill.selector);
_registerFeatureFunction(this.multiHopFill.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Executes a batch of fills selling `fillData.inputToken`
/// for `fillData.outputToken` in sequence. Refer to the
/// internal variant `_batchFill` for the allowed nested
/// operations.
/// @param fillData Encodes the input/output tokens, the sell
/// amount, and the nested operations for this batch fill.
/// @param minBuyAmount The minimum amount of `fillData.outputToken`
/// to buy. Reverts if this amount is not met.
/// @return outputTokenAmount The amount of the output token bought.
function batchFill(
BatchFillData memory fillData,
uint256 minBuyAmount
)
public
payable
override
returns (uint256 outputTokenAmount)
{
// Cache the sender's balance of the output token.
outputTokenAmount = fillData.outputToken.getTokenBalanceOf(msg.sender);
// Cache the contract's ETH balance prior to this call.
uint256 ethBalanceBefore = address(this).balance.safeSub(msg.value);
// Perform the batch fill.
_batchFill(fillData);
// The `outputTokenAmount` returned by `_batchFill` may not
// be fully accurate (e.g. due to some janky token).
outputTokenAmount = fillData.outputToken.getTokenBalanceOf(msg.sender)
.safeSub(outputTokenAmount);
require(
outputTokenAmount >= minBuyAmount,
"MultiplexFeature::batchFill/UNDERBOUGHT"
);
uint256 ethBalanceAfter = address(this).balance;
require(
ethBalanceAfter >= ethBalanceBefore,
"MultiplexFeature::batchFill/OVERSPENT_ETH"
);
// Refund ETH
if (ethBalanceAfter > ethBalanceBefore) {
_transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
}
}
/// @dev Executes a sequence of fills "hopping" through the
/// path of tokens given by `fillData.tokens`. Refer to the
/// internal variant `_multiHopFill` for the allowed nested
/// operations.
/// @param fillData Encodes the path of tokens, the sell amount,
/// and the nested operations for this multi-hop fill.
/// @param minBuyAmount The minimum amount of the output token
/// to buy. Reverts if this amount is not met.
/// @return outputTokenAmount The amount of the output token bought.
function multiHopFill(
MultiHopFillData memory fillData,
uint256 minBuyAmount
)
public
payable
override
returns (uint256 outputTokenAmount)
{
IERC20TokenV06 outputToken = IERC20TokenV06(fillData.tokens[fillData.tokens.length - 1]);
// Cache the sender's balance of the output token.
outputTokenAmount = outputToken.getTokenBalanceOf(msg.sender);
// Cache the contract's ETH balance prior to this call.
uint256 ethBalanceBefore = address(this).balance.safeSub(msg.value);
// Perform the multi-hop fill. Pass in `msg.value` as the maximum
// allowable amount of ETH for the wrapped calls to consume.
_multiHopFill(fillData, msg.value);
// The `outputTokenAmount` returned by `_multiHopFill` may not
// be fully accurate (e.g. due to some janky token).
outputTokenAmount = outputToken.getTokenBalanceOf(msg.sender)
.safeSub(outputTokenAmount);
require(
outputTokenAmount >= minBuyAmount,
"MultiplexFeature::multiHopFill/UNDERBOUGHT"
);
uint256 ethBalanceAfter = address(this).balance;
require(
ethBalanceAfter >= ethBalanceBefore,
"MultiplexFeature::multiHopFill/OVERSPENT_ETH"
);
// Refund ETH
if (ethBalanceAfter > ethBalanceBefore) {
_transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
}
}
// Similar to FQT. If `fillData.sellAmount` is set to `type(uint256).max`,
// this is effectively a batch fill. Otherwise it can be set to perform a
// market sell of some amount. Note that the `outputTokenAmount` returned
// by this function could theoretically be inaccurate if `msg.sender` has
// set a token allowance on an external contract that gets called during
// the execution of this function.
function _batchFill(BatchFillData memory fillData)
internal
returns (uint256 outputTokenAmount, uint256 remainingEth)
{
// Track the remaining ETH allocated to this call.
remainingEth = msg.value;
// Track the amount of input token sold.
uint256 soldAmount;
for (uint256 i = 0; i != fillData.calls.length; i++) {
// Check if we've hit our target.
if (soldAmount >= fillData.sellAmount) { break; }
WrappedBatchCall memory wrappedCall = fillData.calls[i];
// Compute the fill amount.
uint256 inputTokenAmount = LibSafeMathV06.min256(
wrappedCall.sellAmount,
fillData.sellAmount.safeSub(soldAmount)
);
if (wrappedCall.selector == INativeOrdersFeature._fillRfqOrder.selector) {
// Decode the RFQ order and signature.
(
LibNativeOrder.RfqOrder memory order,
LibSignature.Signature memory signature
) = abi.decode(
wrappedCall.data,
(LibNativeOrder.RfqOrder, LibSignature.Signature)
);
if (order.expiry <= uint64(block.timestamp)) {
bytes32 orderHash = _getEIP712Hash(
LibNativeOrder.getRfqOrderStructHash(order)
);
emit ExpiredRfqOrder(
orderHash,
order.maker,
order.expiry
);
continue;
}
require(
order.takerToken == fillData.inputToken &&
order.makerToken == fillData.outputToken,
"MultiplexFeature::_batchFill/RFQ_ORDER_INVALID_TOKENS"
);
// Try filling the RFQ order. Swallows reverts.
try
INativeOrdersFeature(address(this))._fillRfqOrder
(
order,
signature,
inputTokenAmount.safeDowncastToUint128(),
msg.sender
)
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
// Increment the sold and bought amounts.
soldAmount = soldAmount.safeAdd(takerTokenFilledAmount);
outputTokenAmount = outputTokenAmount.safeAdd(makerTokenFilledAmount);
} catch {}
} else if (wrappedCall.selector == this._sellToUniswap.selector) {
(address[] memory tokens, bool isSushi) = abi.decode(
wrappedCall.data,
(address[], bool)
);
require(
tokens.length >= 2 &&
tokens[0] == address(fillData.inputToken) &&
tokens[tokens.length - 1] == address(fillData.outputToken),
"MultiplexFeature::_batchFill/UNISWAP_INVALID_TOKENS"
);
// Perform the Uniswap/Sushiswap trade.
uint256 outputTokenAmount_ = _sellToUniswap(
tokens,
inputTokenAmount,
isSushi,
address(0),
msg.sender
);
// Increment the sold and bought amounts.
soldAmount = soldAmount.safeAdd(inputTokenAmount);
outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
} else if (wrappedCall.selector == this._sellToLiquidityProvider.selector) {
(address provider, bytes memory auxiliaryData) = abi.decode(
wrappedCall.data,
(address, bytes)
);
if (fillData.inputToken.isTokenETH()) {
inputTokenAmount = LibSafeMathV06.min256(
inputTokenAmount,
remainingEth
);
// Transfer the input ETH to the provider.
_transferEth(payable(provider), inputTokenAmount);
// Count that ETH as spent.
remainingEth -= inputTokenAmount;
} else {
// Transfer input ERC20 tokens to the provider.
_transferERC20Tokens(
fillData.inputToken,
msg.sender,
provider,
inputTokenAmount
);
}
// Perform the PLP trade.
uint256 outputTokenAmount_ = _sellToLiquidityProvider(
fillData.inputToken,
fillData.outputToken,
inputTokenAmount,
ILiquidityProvider(provider),
msg.sender,
auxiliaryData
);
// Increment the sold and bought amounts.
soldAmount = soldAmount.safeAdd(inputTokenAmount);
outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
} else if (wrappedCall.selector == ITransformERC20Feature._transformERC20.selector) {
ITransformERC20Feature.TransformERC20Args memory args;
args.taker = msg.sender;
args.inputToken = fillData.inputToken;
args.outputToken = fillData.outputToken;
args.inputTokenAmount = inputTokenAmount;
args.minOutputTokenAmount = 0;
uint256 ethValue;
(args.transformations, ethValue) = abi.decode(
wrappedCall.data,
(ITransformERC20Feature.Transformation[], uint256)
);
// Do not spend more than the remaining ETH.
ethValue = LibSafeMathV06.min256(
ethValue,
remainingEth
);
if (ethValue > 0) {
require(
args.inputToken.isTokenETH(),
"MultiplexFeature::_batchFill/ETH_TRANSFORM_ONLY"
);
}
try ITransformERC20Feature(address(this))._transformERC20
{value: ethValue}
(args)
returns (uint256 outputTokenAmount_)
{
remainingEth -= ethValue;
soldAmount = soldAmount.safeAdd(inputTokenAmount);
outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
} catch {}
} else if (wrappedCall.selector == this._multiHopFill.selector) {
MultiHopFillData memory multiHopFillData;
uint256 ethValue;
(
multiHopFillData.tokens,
multiHopFillData.calls,
ethValue
) = abi.decode(
wrappedCall.data,
(address[], WrappedMultiHopCall[], uint256)
);
multiHopFillData.sellAmount = inputTokenAmount;
// Do not spend more than the remaining ETH.
ethValue = LibSafeMathV06.min256(
ethValue,
remainingEth
);
// Subtract the ethValue allocated to the nested multi-hop fill.
remainingEth -= ethValue;
(uint256 outputTokenAmount_, uint256 leftoverEth) =
_multiHopFill(multiHopFillData, ethValue);
// Increment the sold and bought amounts.
soldAmount = soldAmount.safeAdd(inputTokenAmount);
outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
// Add back any ETH that wasn't used by the nested multi-hop fill.
remainingEth += leftoverEth;
} else {
revert("MultiplexFeature::_batchFill/UNRECOGNIZED_SELECTOR");
}
}
}
// Internal variant of `multiHopFill`. This function can be nested within
// a `_batchFill`.
// This function executes a sequence of fills "hopping" through the
// path of tokens given by `fillData.tokens`. The nested operations that
// can be used as "hops" are:
// - WETH.deposit (wraps ETH)
// - WETH.withdraw (unwraps WETH)
// - _sellToUniswap (executes a Uniswap/Sushiswap swap)
// - _sellToLiquidityProvider (executes a PLP swap)
// - _transformERC20 (executes arbitrary ERC20 Transformations)
// This function optimizes the number of ERC20 transfers performed
// by having each hop transfer its output tokens directly to the
// target address of the next hop. Note that the `outputTokenAmount` returned
// by this function could theoretically be inaccurate if `msg.sender` has
// set a token allowance on an external contract that gets called during
// the execution of this function.
function _multiHopFill(MultiHopFillData memory fillData, uint256 totalEth)
public
returns (uint256 outputTokenAmount, uint256 remainingEth)
{
// There should be one call/hop between every two tokens
// in the path.
// tokens[0]calls[0]>tokens[1]...calls[n-1]>tokens[n]
require(
fillData.tokens.length == fillData.calls.length + 1,
"MultiplexFeature::_multiHopFill/MISMATCHED_ARRAY_LENGTHS"
);
// Track the remaining ETH allocated to this call.
remainingEth = totalEth;
// This variable is used as the input and output amounts of
// each hop. After the final hop, this will contain the output
// amount of the multi-hop fill.
outputTokenAmount = fillData.sellAmount;
// This variable is used to cache the address to target in the
// next hop. See `_computeHopRecipient` for details.
address nextTarget;
for (uint256 i = 0; i != fillData.calls.length; i++) {
WrappedMultiHopCall memory wrappedCall = fillData.calls[i];
if (wrappedCall.selector == this._sellToUniswap.selector) {
// If the next hop supports a "transfer then execute" pattern,
// the recipient will not be `msg.sender`. See `_computeHopRecipient`
// for details.
address recipient = _computeHopRecipient(fillData.calls, i);
(address[] memory tokens, bool isSushi) = abi.decode(
wrappedCall.data,
(address[], bool)
);
// Perform the Uniswap/Sushiswap trade.
outputTokenAmount = _sellToUniswap(
tokens,
outputTokenAmount,
isSushi,
nextTarget,
recipient
);
// If the recipient was not `msg.sender`, it must be the target
// contract for the next hop.
nextTarget = recipient == msg.sender ? address(0) : recipient;
} else if (wrappedCall.selector == this._sellToLiquidityProvider.selector) {
// If the next hop supports a "transfer then execute" pattern,
// the recipient will not be `msg.sender`. See `_computeHopRecipient`
// for details.
address recipient = _computeHopRecipient(fillData.calls, i);
// If `nextTarget` was not set in the previous hop, then we
// need to send in the input ETH/tokens to the liquidity provider
// contract before executing the trade.
if (nextTarget == address(0)) {
(address provider, bytes memory auxiliaryData) = abi.decode(
wrappedCall.data,
(address, bytes)
);
// Transfer input ETH or ERC20 tokens to the liquidity
// provider contract.
if (IERC20TokenV06(fillData.tokens[i]).isTokenETH()) {
outputTokenAmount = LibSafeMathV06.min256(
outputTokenAmount,
remainingEth
);
_transferEth(payable(provider), outputTokenAmount);
remainingEth -= outputTokenAmount;
} else {
_transferERC20Tokens(
IERC20TokenV06(fillData.tokens[i]),
msg.sender,
provider,
outputTokenAmount
);
}
outputTokenAmount = _sellToLiquidityProvider(
IERC20TokenV06(fillData.tokens[i]),
IERC20TokenV06(fillData.tokens[i + 1]),
outputTokenAmount,
ILiquidityProvider(provider),
recipient,
auxiliaryData
);
} else {
(, bytes memory auxiliaryData) = abi.decode(
wrappedCall.data,
(address, bytes)
);
// Tokens and ETH have already been transferred to
// the liquidity provider contract in the previous hop.
outputTokenAmount = _sellToLiquidityProvider(
IERC20TokenV06(fillData.tokens[i]),
IERC20TokenV06(fillData.tokens[i + 1]),
outputTokenAmount,
ILiquidityProvider(nextTarget),
recipient,
auxiliaryData
);
}
// If the recipient was not `msg.sender`, it must be the target
// contract for the next hop.
nextTarget = recipient == msg.sender ? address(0) : recipient;
} else if (wrappedCall.selector == ITransformERC20Feature._transformERC20.selector) {
ITransformERC20Feature.TransformERC20Args memory args;
args.inputToken = IERC20TokenV06(fillData.tokens[i]);
args.outputToken = IERC20TokenV06(fillData.tokens[i + 1]);
args.minOutputTokenAmount = 0;
args.taker = payable(_computeHopRecipient(fillData.calls, i));
if (nextTarget != address(0)) {
// If `nextTarget` was set in the previous hop, then the input
// token was already sent to the FlashWallet. Setting
// `inputTokenAmount` to 0 indicates that no tokens need to
// be pulled into the FlashWallet before executing the
// transformations.
args.inputTokenAmount = 0;
} else if (
args.taker != msg.sender &&
!args.inputToken.isTokenETH()
) {
address flashWallet = address(
ITransformERC20Feature(address(this)).getTransformWallet()
);
// The input token has _not_ already been sent to the
// FlashWallet. We also want PayTakerTransformer to
// send the output token to some address other than
// msg.sender, so we must transfer the input token
// to the FlashWallet here.
_transferERC20Tokens(
args.inputToken,
msg.sender,
flashWallet,
outputTokenAmount
);
args.inputTokenAmount = 0;
} else {
// Otherwise, either:
// (1) args.taker == msg.sender, in which case
// `_transformERC20` will pull the input token
// into the FlashWallet, or
// (2) args.inputToken == ETH_TOKEN_ADDRESS, in which
// case ETH is attached to the call and no token
// transfer occurs.
args.inputTokenAmount = outputTokenAmount;
}
uint256 ethValue;
(args.transformations, ethValue) = abi.decode(
wrappedCall.data,
(ITransformERC20Feature.Transformation[], uint256)
);
// Do not spend more than the remaining ETH.
ethValue = LibSafeMathV06.min256(ethValue, remainingEth);
if (ethValue > 0) {
require(
args.inputToken.isTokenETH(),
"MultiplexFeature::_multiHopFill/ETH_TRANSFORM_ONLY"
);
}
// Call `_transformERC20`.
outputTokenAmount = ITransformERC20Feature(address(this))
._transformERC20{value: ethValue}(args);
// Decrement the remaining ETH.
remainingEth -= ethValue;
// If the recipient was not `msg.sender`, it must be the target
// contract for the next hop.
nextTarget = args.taker == msg.sender ? address(0) : args.taker;
} else if (wrappedCall.selector == IEtherTokenV06.deposit.selector) {
require(
i == 0,
"MultiplexFeature::_multiHopFill/DEPOSIT_FIRST_HOP_ONLY"
);
uint256 ethValue = LibSafeMathV06.min256(outputTokenAmount, remainingEth);
// Wrap ETH.
weth.deposit{value: ethValue}();
nextTarget = _computeHopRecipient(fillData.calls, i);
weth.transfer(nextTarget, ethValue);
remainingEth -= ethValue;
} else if (wrappedCall.selector == IEtherTokenV06.withdraw.selector) {
require(
i == fillData.calls.length - 1,
"MultiplexFeature::_multiHopFill/WITHDRAW_LAST_HOP_ONLY"
);
// Unwrap WETH and send to `msg.sender`.
weth.withdraw(outputTokenAmount);
_transferEth(msg.sender, outputTokenAmount);
nextTarget = address(0);
} else {
revert("MultiplexFeature::_multiHopFill/UNRECOGNIZED_SELECTOR");
}
}
}
// Similar to the UniswapFeature, but with a couple of differences:
// - Does not perform the transfer in if `pairAddress` is given,
// which indicates that the transfer in was already performed
// in the previous hop of a multi-hop fill.
// - Does not include a minBuyAmount check (which is performed in
// either `batchFill` or `multiHopFill`).
// - Takes a `recipient` address parameter, so the output of the
// final `swap` call can be sent to an address other than `msg.sender`.
function _sellToUniswap(
address[] memory tokens,
uint256 sellAmount,
bool isSushi,
address pairAddress,
address recipient
)
public
returns (uint256 outputTokenAmount)
{
require(tokens.length > 1, "MultiplexFeature::_sellToUniswap/InvalidTokensLength");
if (pairAddress == address(0)) {
pairAddress = _computeUniswapPairAddress(tokens[0], tokens[1], isSushi);
_transferERC20Tokens(
IERC20TokenV06(tokens[0]),
msg.sender,
pairAddress,
sellAmount
);
}
for (uint256 i = 0; i < tokens.length - 1; i++) {
(address inputToken, address outputToken) = (tokens[i], tokens[i + 1]);
outputTokenAmount = _computeUniswapOutputAmount(
pairAddress,
inputToken,
outputToken,
sellAmount
);
(uint256 amount0Out, uint256 amount1Out) = inputToken < outputToken
? (uint256(0), outputTokenAmount)
: (outputTokenAmount, uint256(0));
address to = i < tokens.length - 2
? _computeUniswapPairAddress(outputToken, tokens[i + 2], isSushi)
: recipient;
IUniswapV2Pair(pairAddress).swap(
amount0Out,
amount1Out,
to,
new bytes(0)
);
pairAddress = to;
sellAmount = outputTokenAmount;
}
}
// Same as the LiquidityProviderFeature, but without the transfer in
// (which is potentially done in the previous hop of a multi-hop fill)
// and without the minBuyAmount check (which is performed at the top, i.e.
// in either `batchFill` or `multiHopFill`).
function _sellToLiquidityProvider(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
ILiquidityProvider provider,
address recipient,
bytes memory auxiliaryData
)
public
returns (uint256 outputTokenAmount)
{
uint256 balanceBefore = IERC20TokenV06(outputToken).getTokenBalanceOf(recipient);
if (IERC20TokenV06(inputToken).isTokenETH()) {
sandbox.executeSellEthForToken(
provider,
outputToken,
recipient,
0,
auxiliaryData
);
} else if (IERC20TokenV06(outputToken).isTokenETH()) {
sandbox.executeSellTokenForEth(
provider,
inputToken,
recipient,
0,
auxiliaryData
);
} else {
sandbox.executeSellTokenForToken(
provider,
inputToken,
outputToken,
recipient,
0,
auxiliaryData
);
}
outputTokenAmount = IERC20TokenV06(outputToken).getTokenBalanceOf(recipient)
.safeSub(balanceBefore);
emit LiquidityProviderSwap(
address(inputToken),
address(outputToken),
inputTokenAmount,
outputTokenAmount,
address(provider),
recipient
);
return outputTokenAmount;
}
function _transferEth(address payable recipient, uint256 amount)
private
{
(bool success,) = recipient.call{value: amount}("");
require(success, "MultiplexFeature::_transferEth/TRANSFER_FALIED");
}
// Some liquidity sources (e.g. Uniswap, Sushiswap, and PLP) can be passed
// a `recipient` parameter so the boguht tokens are transferred to the
// `recipient` address rather than `msg.sender`.
// Some liquidity sources (also Uniswap, Sushiswap, and PLP incidentally)
// support a "transfer then execute" pattern, where the token being sold
// can be transferred into the contract before calling a swap function to
// execute the trade.
// If the current hop in a multi-hop fill satisfies the first condition,
// and the next hop satisfies the second condition, the tokens bought
// in the current hop can be directly sent to the target contract of
// the next hop to save a transfer.
function _computeHopRecipient(
WrappedMultiHopCall[] memory calls,
uint256 i
)
private
view
returns (address recipient)
{
recipient = msg.sender;
if (i < calls.length - 1) {
WrappedMultiHopCall memory nextCall = calls[i + 1];
if (nextCall.selector == this._sellToUniswap.selector) {
(address[] memory tokens, bool isSushi) = abi.decode(
nextCall.data,
(address[], bool)
);
recipient = _computeUniswapPairAddress(tokens[0], tokens[1], isSushi);
} else if (nextCall.selector == this._sellToLiquidityProvider.selector) {
(recipient,) = abi.decode(
nextCall.data,
(address, bytes)
);
} else if (nextCall.selector == IEtherTokenV06.withdraw.selector) {
recipient = address(this);
} else if (nextCall.selector == ITransformERC20Feature._transformERC20.selector) {
recipient = address(
ITransformERC20Feature(address(this)).getTransformWallet()
);
}
}
require(
recipient != address(0),
"MultiplexFeature::_computeHopRecipient/RECIPIENT_IS_NULL"
);
}
// Computes the the amount of output token that would be bought
// from Uniswap/Sushiswap given the input amount.
function _computeUniswapOutputAmount(
address pairAddress,
address inputToken,
address outputToken,
uint256 inputAmount
)
private
view
returns (uint256 outputAmount)
{
require(
inputAmount > 0,
"MultiplexFeature::_computeUniswapOutputAmount/INSUFFICIENT_INPUT_AMOUNT"
);
(uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(pairAddress).getReserves();
require(
reserve0 > 0 && reserve1 > 0,
'MultiplexFeature::_computeUniswapOutputAmount/INSUFFICIENT_LIQUIDITY'
);
(uint256 inputReserve, uint256 outputReserve) = inputToken < outputToken
? (reserve0, reserve1)
: (reserve1, reserve0);
uint256 inputAmountWithFee = inputAmount.safeMul(997);
uint256 numerator = inputAmountWithFee.safeMul(outputReserve);
uint256 denominator = inputReserve.safeMul(1000).safeAdd(inputAmountWithFee);
return numerator / denominator;
}
// Computes the Uniswap/Sushiswap pair contract address for the
// given tokens.
function _computeUniswapPairAddress(
address tokenA,
address tokenB,
bool isSushi
)
private
pure
returns (address pairAddress)
{
(address token0, address token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
if (isSushi) {
return address(uint256(keccak256(abi.encodePacked(
hex'ff',
SUSHISWAP_FACTORY,
keccak256(abi.encodePacked(token0, token1)),
SUSHISWAP_PAIR_INIT_CODE_HASH
))));
} else {
return address(uint256(keccak256(abi.encodePacked(
hex'ff',
UNISWAP_FACTORY,
keccak256(abi.encodePacked(token0, token1)),
UNISWAP_PAIR_INIT_CODE_HASH
))));
}
}
}

View File

@@ -26,8 +26,8 @@ import "../errors/LibOwnableRichErrors.sol";
import "../storage/LibOwnableStorage.sol";
import "../migrations/LibBootstrap.sol";
import "../migrations/LibMigrate.sol";
import "./IFeature.sol";
import "./IOwnableFeature.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IOwnableFeature.sol";
import "./SimpleFunctionRegistryFeature.sol";

View File

@@ -0,0 +1,423 @@
// 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 "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../migrations/LibMigrate.sol";
import "../fixins/FixinCommon.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IPancakeSwapFeature.sol";
/// @dev VIP pancake fill functions.
contract PancakeSwapFeature is
IFeature,
IPancakeSwapFeature,
FixinCommon
{
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "PancakeSwapFeature";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 1);
/// @dev WBNB contract.
IEtherTokenV06 private immutable WBNB;
// 0xFF + address of the PancakeSwap factory contract.
uint256 constant private FF_PANCAKESWAP_FACTORY = 0xffbcfccbde45ce874adcb698cc183debcf179528120000000000000000000000;
// 0xFF + address of the BakerySwap factory contract.
uint256 constant private FF_BAKERYSWAP_FACTORY = 0xff01bf7c66c6bd861915cdaae475042d3c4bae16a70000000000000000000000;
// 0xFF + address of the SushiSwap factory contract.
uint256 constant private FF_SUSHISWAP_FACTORY = 0xffc35DADB65012eC5796536bD9864eD8773aBc74C40000000000000000000000;
// Init code hash of the PancakeSwap pair contract.
uint256 constant private PANCAKESWAP_PAIR_INIT_CODE_HASH = 0xd0d4c4cd0848c93cb4fd1f498d7013ee6bfb25783ea21593d5834f5d250ece66;
// Init code hash of the BakerySwap pair contract.
uint256 constant private BAKERYSWAP_PAIR_INIT_CODE_HASH = 0xe2e87433120e32c4738a7d8f3271f3d872cbe16241d67537139158d90bac61d3;
// Init code hash of the SushiSwap pair contract.
uint256 constant private SUSHISWAP_PAIR_INIT_CODE_HASH = 0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303;
// Mask of the lower 20 bytes of a bytes32.
uint256 constant private ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff;
// BNB pseudo-token address.
uint256 constant private ETH_TOKEN_ADDRESS_32 = 0x000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;
// Maximum token quantity that can be swapped against the PancakeSwapPair contract.
uint256 constant private MAX_SWAP_AMOUNT = 2**112;
// bytes4(keccak256("executeCall(address,bytes)"))
uint256 constant private ALLOWANCE_TARGET_EXECUTE_CALL_SELECTOR_32 = 0xbca8c7b500000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("getReserves()"))
uint256 constant private PANCAKESWAP_PAIR_RESERVES_CALL_SELECTOR_32 = 0x0902f1ac00000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("swap(uint256,uint256,address,bytes)"))
uint256 constant private PANCAKESWAP_PAIR_SWAP_CALL_SELECTOR_32 = 0x022c0d9f00000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("swap(uint256,uint256,address)"))
uint256 constant private BAKERYSWAP_PAIR_SWAP_CALL_SELECTOR_32 = 0x6d9a640a00000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("transferFrom(address,address,uint256)"))
uint256 constant private TRANSFER_FROM_CALL_SELECTOR_32 = 0x23b872dd00000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("allowance(address,address)"))
uint256 constant private ALLOWANCE_CALL_SELECTOR_32 = 0xdd62ed3e00000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("withdraw(uint256)"))
uint256 constant private WETH_WITHDRAW_CALL_SELECTOR_32 = 0x2e1a7d4d00000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("deposit()"))
uint256 constant private WETH_DEPOSIT_CALL_SELECTOR_32 = 0xd0e30db000000000000000000000000000000000000000000000000000000000;
// bytes4(keccak256("transfer(address,uint256)"))
uint256 constant private ERC20_TRANSFER_CALL_SELECTOR_32 = 0xa9059cbb00000000000000000000000000000000000000000000000000000000;
/// @dev Construct this contract.
/// @param wbnb The WBNB contract.
constructor(IEtherTokenV06 wbnb) public {
WBNB = wbnb;
}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
/// @return success `LibMigrate.SUCCESS` on success.
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.sellToPancakeSwap.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Efficiently sell directly to pancake/BakerySwap/SushiSwap.
/// @param tokens Sell path.
/// @param sellAmount of `tokens[0]` Amount to sell.
/// @param minBuyAmount Minimum amount of `tokens[-1]` to buy.
/// @param fork The protocol fork to use.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToPancakeSwap(
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
ProtocolFork fork
)
external
payable
override
returns (uint256 buyAmount)
{
require(tokens.length > 1, "PancakeSwapFeature/InvalidTokensLength");
{
// Load immutables onto the stack.
IEtherTokenV06 wbnb = WBNB;
// Store some vars in memory to get around stack limits.
assembly {
// calldataload(mload(0xA00)) == first element of `tokens` array
mstore(0xA00, add(calldataload(0x04), 0x24))
// mload(0xA20) == fork
mstore(0xA20, fork)
// mload(0xA40) == WBNB
mstore(0xA40, wbnb)
}
}
assembly {
// numPairs == tokens.length - 1
let numPairs := sub(calldataload(add(calldataload(0x04), 0x4)), 1)
// We use the previous buy amount as the sell amount for the next
// pair in a path. So for the first swap we want to set it to `sellAmount`.
buyAmount := sellAmount
let buyToken
let nextPair := 0
for {let i := 0} lt(i, numPairs) {i := add(i, 1)} {
// sellToken = tokens[i]
let sellToken := loadTokenAddress(i)
// buyToken = tokens[i+1]
buyToken := loadTokenAddress(add(i, 1))
// The canonical ordering of this token pair.
let pairOrder := lt(normalizeToken(sellToken), normalizeToken(buyToken))
// Compute the pair address if it hasn't already been computed
// from the last iteration.
let pair := nextPair
if iszero(pair) {
pair := computePairAddress(sellToken, buyToken)
nextPair := 0
}
if iszero(i) {
// This is the first token in the path.
switch eq(sellToken, ETH_TOKEN_ADDRESS_32)
case 0 { // Not selling BNB. Selling an ERC20 instead.
// Make sure BNB was not attached to the call.
if gt(callvalue(), 0) {
revert(0, 0)
}
// For the first pair we need to transfer sellTokens into the
// pair contract.
moveTakerTokensTo(sellToken, pair, sellAmount)
}
default {
// If selling BNB, we need to wrap it to WBNB and transfer to the
// pair contract.
if iszero(eq(callvalue(), sellAmount)) {
revert(0, 0)
}
sellToken := mload(0xA40)// Re-assign to WBNB
// Call `WBNB.deposit{value: sellAmount}()`
mstore(0xB00, WETH_DEPOSIT_CALL_SELECTOR_32)
if iszero(call(gas(), sellToken, sellAmount, 0xB00, 0x4, 0x00, 0x0)) {
bubbleRevert()
}
// Call `WBNB.transfer(pair, sellAmount)`
mstore(0xB00, ERC20_TRANSFER_CALL_SELECTOR_32)
mstore(0xB04, pair)
mstore(0xB24, sellAmount)
if iszero(call(gas(), sellToken, 0, 0xB00, 0x44, 0x00, 0x0)) {
bubbleRevert()
}
}
// No need to check results, if deposit/transfers failed the PancakeSwapPair will
// reject our trade (or it may succeed if somehow the reserve was out of sync)
// this is fine for the taker.
}
// Call pair.getReserves(), store the results at `0xC00`
mstore(0xB00, PANCAKESWAP_PAIR_RESERVES_CALL_SELECTOR_32)
if iszero(staticcall(gas(), pair, 0xB00, 0x4, 0xC00, 0x40)) {
bubbleRevert()
}
// Revert if the pair contract does not return at least two words.
if lt(returndatasize(), 0x40) {
mstore(0, pair)
revert(0, 32)
}
// Sell amount for this hop is the previous buy amount.
let pairSellAmount := buyAmount
// Compute the buy amount based on the pair reserves.
{
let sellReserve
let buyReserve
switch iszero(pairOrder)
case 0 {
// Transpose if pair order is different.
sellReserve := mload(0xC00)
buyReserve := mload(0xC20)
}
default {
sellReserve := mload(0xC20)
buyReserve := mload(0xC00)
}
// Ensure that the sellAmount is < 2¹¹².
if gt(pairSellAmount, MAX_SWAP_AMOUNT) {
revert(0, 0)
}
// Pairs are in the range (0, 2¹¹²) so this shouldn't overflow.
// buyAmount = (pairSellAmount * 997 * buyReserve) /
// (pairSellAmount * 997 + sellReserve * 1000);
let sellAmountWithFee := mul(pairSellAmount, 997)
buyAmount := div(
mul(sellAmountWithFee, buyReserve),
add(sellAmountWithFee, mul(sellReserve, 1000))
)
}
let receiver
// Is this the last pair contract?
switch eq(add(i, 1), numPairs)
case 0 {
// Not the last pair contract, so forward bought tokens to
// the next pair contract.
nextPair := computePairAddress(
buyToken,
loadTokenAddress(add(i, 2))
)
receiver := nextPair
}
default {
// The last pair contract.
// Forward directly to taker UNLESS they want BNB back.
switch eq(buyToken, ETH_TOKEN_ADDRESS_32)
case 0 {
receiver := caller()
}
default {
receiver := address()
}
}
// Call pair.swap()
switch mload(0xA20) // fork
case 1 {
mstore(0xB00, BAKERYSWAP_PAIR_SWAP_CALL_SELECTOR_32)
}
default {
mstore(0xB00, PANCAKESWAP_PAIR_SWAP_CALL_SELECTOR_32)
}
switch pairOrder
case 0 {
mstore(0xB04, buyAmount)
mstore(0xB24, 0)
}
default {
mstore(0xB04, 0)
mstore(0xB24, buyAmount)
}
mstore(0xB44, receiver)
mstore(0xB64, 0x80)
mstore(0xB84, 0)
if iszero(call(gas(), pair, 0, 0xB00, 0xA4, 0, 0)) {
bubbleRevert()
}
} // End for-loop.
// If buying BNB, unwrap the WBNB first
if eq(buyToken, ETH_TOKEN_ADDRESS_32) {
// Call `WBNB.withdraw(buyAmount)`
mstore(0xB00, WETH_WITHDRAW_CALL_SELECTOR_32)
mstore(0xB04, buyAmount)
if iszero(call(gas(), mload(0xA40), 0, 0xB00, 0x24, 0x00, 0x0)) {
bubbleRevert()
}
// Transfer BNB to the caller.
if iszero(call(gas(), caller(), buyAmount, 0xB00, 0x0, 0x00, 0x0)) {
bubbleRevert()
}
}
// Functions ///////////////////////////////////////////////////////
// Load a token address from the `tokens` calldata argument.
function loadTokenAddress(idx) -> addr {
addr := and(ADDRESS_MASK, calldataload(add(mload(0xA00), mul(idx, 0x20))))
}
// Convert BNB pseudo-token addresses to WBNB.
function normalizeToken(token) -> normalized {
normalized := token
// Translate BNB pseudo-tokens to WBNB.
if eq(token, ETH_TOKEN_ADDRESS_32) {
normalized := mload(0xA40)
}
}
// Compute the address of the PancakeSwapPair contract given two
// tokens.
function computePairAddress(tokenA, tokenB) -> pair {
// Convert BNB pseudo-token addresses to WBNB.
tokenA := normalizeToken(tokenA)
tokenB := normalizeToken(tokenB)
// There is one contract for every combination of tokens,
// which is deployed using CREATE2.
// The derivation of this address is given by:
// address(keccak256(abi.encodePacked(
// bytes(0xFF),
// address(PANCAKESWAP_FACTORY_ADDRESS),
// keccak256(abi.encodePacked(
// tokenA < tokenB ? tokenA : tokenB,
// tokenA < tokenB ? tokenB : tokenA,
// )),
// bytes32(PANCAKESWAP_PAIR_INIT_CODE_HASH),
// )));
// Compute the salt (the hash of the sorted tokens).
// Tokens are written in reverse memory order to packed encode
// them as two 20-byte values in a 40-byte chunk of memory
// starting at 0xB0C.
switch lt(tokenA, tokenB)
case 0 {
mstore(0xB14, tokenA)
mstore(0xB00, tokenB)
}
default {
mstore(0xB14, tokenB)
mstore(0xB00, tokenA)
}
let salt := keccak256(0xB0C, 0x28)
// Compute the pair address by hashing all the components together.
switch mload(0xA20) // fork
case 0 {
mstore(0xB00, FF_PANCAKESWAP_FACTORY)
mstore(0xB15, salt)
mstore(0xB35, PANCAKESWAP_PAIR_INIT_CODE_HASH)
}
case 1 {
mstore(0xB00, FF_BAKERYSWAP_FACTORY)
mstore(0xB15, salt)
mstore(0xB35, BAKERYSWAP_PAIR_INIT_CODE_HASH)
}
default {
mstore(0xB00, FF_SUSHISWAP_FACTORY)
mstore(0xB15, salt)
mstore(0xB35, SUSHISWAP_PAIR_INIT_CODE_HASH)
}
pair := and(ADDRESS_MASK, keccak256(0xB00, 0x55))
}
// Revert with the return data from the most recent call.
function bubbleRevert() {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
// Move `amount` tokens from the taker/caller to `to`.
function moveTakerTokensTo(token, to, amount) {
// Perform a `transferFrom()`
mstore(0xB00, TRANSFER_FROM_CALL_SELECTOR_32)
mstore(0xB04, caller())
mstore(0xB24, to)
mstore(0xB44, amount)
let success := call(
gas(),
token,
0,
0xB00,
0x64,
0xC00,
// Copy only the first 32 bytes of return data. We
// only care about reading a boolean in the success
// case. We will use returndatacopy() in the failure case.
0x20
)
let rdsize := returndatasize()
// Check for ERC20 success. ERC20 tokens should
// return a boolean, but some return nothing or
// extra data. We accept 0-length return data as
// success, or at least 32 bytes that starts with
// a 32-byte boolean true.
success := and(
success, // call itself succeeded
or(
iszero(rdsize), // no return data, or
and(
iszero(lt(rdsize, 32)), // at least 32 bytes
eq(mload(0xC00), 1) // starts with uint256(1)
)
)
)
if iszero(success) {
// Revert with the data returned from the transferFrom call.
returndatacopy(0, 0, rdsize)
revert(0, rdsize)
}
}
}
// Revert if we bought too little.
require(buyAmount >= minBuyAmount, "PancakeSwapFeature/UnderBought");
}
}

View File

@@ -26,8 +26,8 @@ import "../storage/LibProxyStorage.sol";
import "../storage/LibSimpleFunctionRegistryStorage.sol";
import "../errors/LibSimpleFunctionRegistryRichErrors.sol";
import "../migrations/LibBootstrap.sol";
import "./IFeature.sol";
import "./ISimpleFunctionRegistryFeature.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/ISimpleFunctionRegistryFeature.sol";
/// @dev Basic registry management features.

View File

@@ -1,137 +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;
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/LibSpenderRichErrors.sol";
import "../fixins/FixinCommon.sol";
import "../migrations/LibMigrate.sol";
import "../external/IAllowanceTarget.sol";
import "../storage/LibTokenSpenderStorage.sol";
import "./ITokenSpenderFeature.sol";
import "./IFeature.sol";
/// @dev Feature that allows spending token allowances.
contract TokenSpenderFeature is
IFeature,
ITokenSpenderFeature,
FixinCommon
{
// solhint-disable
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "TokenSpender";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
// solhint-enable
using LibRichErrorsV06 for bytes;
/// @dev Initialize and register this feature. Should be delegatecalled
/// into during a `Migrate.migrate()`.
/// @param allowanceTarget An `allowanceTarget` instance, configured to have
/// the ZeroeEx contract as an authority.
/// @return success `MIGRATE_SUCCESS` on success.
function migrate(IAllowanceTarget allowanceTarget)
external
returns (bytes4 success)
{
LibTokenSpenderStorage.getStorage().allowanceTarget = allowanceTarget;
_registerFeatureFunction(this.getAllowanceTarget.selector);
_registerFeatureFunction(this._spendERC20Tokens.selector);
_registerFeatureFunction(this.getSpendableERC20BalanceOf.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Transfers ERC20 tokens from `owner` to `to`. Only callable from within.
/// @param token The token to spend.
/// @param owner The owner of the tokens.
/// @param to The recipient of the tokens.
/// @param amount The amount of `token` to transfer.
function _spendERC20Tokens(
IERC20TokenV06 token,
address owner,
address to,
uint256 amount
)
external
override
onlySelf
{
IAllowanceTarget spender = LibTokenSpenderStorage.getStorage().allowanceTarget;
// Have the allowance target execute an ERC20 `transferFrom()`.
(bool didSucceed, bytes memory resultData) = address(spender).call(
abi.encodeWithSelector(
IAllowanceTarget.executeCall.selector,
address(token),
abi.encodeWithSelector(
IERC20TokenV06.transferFrom.selector,
owner,
to,
amount
)
)
);
if (didSucceed) {
resultData = abi.decode(resultData, (bytes));
}
if (!didSucceed || !LibERC20TokenV06.isSuccessfulResult(resultData)) {
LibSpenderRichErrors.SpenderERC20TransferFromFailedError(
address(token),
owner,
to,
amount,
resultData
).rrevert();
}
}
/// @dev Gets the maximum amount of an ERC20 token `token` that can be
/// pulled from `owner` by the token spender.
/// @param token The token to spend.
/// @param owner The owner of the tokens.
/// @return amount The amount of tokens that can be pulled.
function getSpendableERC20BalanceOf(IERC20TokenV06 token, address owner)
external
override
view
returns (uint256 amount)
{
return LibSafeMathV06.min256(
token.allowance(owner, address(LibTokenSpenderStorage.getStorage().allowanceTarget)),
token.balanceOf(owner)
);
}
/// @dev Get the address of the allowance target.
/// @return target The target of token allowances.
function getAllowanceTarget()
external
override
view
returns (address target)
{
return address(LibTokenSpenderStorage.getStorage().allowanceTarget);
}
}

View File

@@ -33,8 +33,8 @@ import "../external/FlashWallet.sol";
import "../storage/LibTransformERC20Storage.sol";
import "../transformers/IERC20Transformer.sol";
import "../transformers/LibERC20Transformer.sol";
import "./ITransformERC20Feature.sol";
import "./IFeature.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/ITransformERC20Feature.sol";
/// @dev Feature to composably transform between ERC20 tokens.
@@ -60,10 +60,7 @@ contract TransformERC20Feature is
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 3, 1);
constructor(bytes32 greedyTokensBloomFilter)
public
FixinTokenSpender(greedyTokensBloomFilter)
{}
constructor() public {}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
@@ -313,7 +310,7 @@ contract TransformERC20Feature is
to.transfer(msg.value);
}
// Transfer input tokens.
if (!LibERC20Transformer.isTokenETH(inputToken)) {
if (!LibERC20Transformer.isTokenETH(inputToken) && amount != 0) {
// Token is not ETH, so pull ERC20 tokens.
_transferERC20Tokens(
inputToken,

View File

@@ -23,10 +23,9 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../migrations/LibMigrate.sol";
import "../external/IAllowanceTarget.sol";
import "../fixins/FixinCommon.sol";
import "./IFeature.sol";
import "./IUniswapFeature.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IUniswapFeature.sol";
/// @dev VIP uniswap fill functions.
@@ -38,13 +37,9 @@ contract UniswapFeature is
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "UniswapFeature";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 1);
/// @dev A bloom filter for tokens that consume all gas when `transferFrom()` fails.
bytes32 public immutable GREEDY_TOKENS_BLOOM_FILTER;
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 2);
/// @dev WETH contract.
IEtherTokenV06 private immutable WETH;
/// @dev AllowanceTarget instance.
IAllowanceTarget private immutable ALLOWANCE_TARGET;
// 0xFF + address of the UniswapV2Factory contract.
uint256 constant private FF_UNISWAP_FACTORY = 0xFF5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f0000000000000000000000;
@@ -80,16 +75,8 @@ contract UniswapFeature is
/// @dev Construct this contract.
/// @param weth The WETH contract.
/// @param allowanceTarget The AllowanceTarget contract.
/// @param greedyTokensBloomFilter The bloom filter for greedy tokens.
constructor(
IEtherTokenV06 weth,
IAllowanceTarget allowanceTarget,
bytes32 greedyTokensBloomFilter
) public {
constructor(IEtherTokenV06 weth) public {
WETH = weth;
ALLOWANCE_TARGET = allowanceTarget;
GREEDY_TOKENS_BLOOM_FILTER = greedyTokensBloomFilter;
}
/// @dev Initialize and register this feature.
@@ -124,8 +111,6 @@ contract UniswapFeature is
{
// Load immutables onto the stack.
IEtherTokenV06 weth = WETH;
IAllowanceTarget allowanceTarget = ALLOWANCE_TARGET;
bytes32 greedyTokensBloomFilter = GREEDY_TOKENS_BLOOM_FILTER;
// Store some vars in memory to get around stack limits.
assembly {
@@ -135,10 +120,6 @@ contract UniswapFeature is
mstore(0xA20, isSushi)
// mload(0xA40) == WETH
mstore(0xA40, weth)
// mload(0xA60) == ALLOWANCE_TARGET
mstore(0xA60, allowanceTarget)
// mload(0xA80) == GREEDY_TOKENS_BLOOM_FILTER
mstore(0xA80, greedyTokensBloomFilter)
}
}
@@ -373,38 +354,7 @@ contract UniswapFeature is
// Move `amount` tokens from the taker/caller to `to`.
function moveTakerTokensTo(token, to, amount) {
// If the token is possibly greedy, we check the allowance rather
// than relying on letting the transferFrom() call fail and
// falling through to legacy allowance target because the token
// will eat all our gas.
if isTokenPossiblyGreedy(token) {
// Check if we have enough direct allowance by calling
// `token.allowance()``
mstore(0xB00, ALLOWANCE_CALL_SELECTOR_32)
mstore(0xB04, caller())
mstore(0xB24, address())
let success := staticcall(gas(), token, 0xB00, 0x44, 0xC00, 0x20)
if iszero(success) {
// Call to allowance() failed.
bubbleRevert()
}
// Make sure the allowance call returned at least a word.
if lt(returndatasize(), 0x20) {
revert(0, 0)
}
// Call succeeded.
// Result is stored in 0xC00-0xC20.
if lt(mload(0xC00), amount) {
// We don't have enough direct allowance, so try
// going through the legacy allowance taregt.
moveTakerTokensToWithLegacyAllowanceTarget(token, to, amount)
leave
}
}
// Otherwise we will optimistically try to perform a `transferFrom()`
// directly then if it fails we will go through the legacy allowance target.
// Perform a `transferFrom()`
mstore(0xB00, TRANSFER_FROM_CALL_SELECTOR_32)
mstore(0xB04, caller())
mstore(0xB24, to)
@@ -419,8 +369,7 @@ contract UniswapFeature is
0xC00,
// Copy only the first 32 bytes of return data. We
// only care about reading a boolean in the success
// case, and we discard the return data in the
// failure case.
// case. We will use returndatacopy() in the failure case.
0x20
)
@@ -443,37 +392,11 @@ contract UniswapFeature is
)
if iszero(success) {
// Try to fall back to the allowance target.
moveTakerTokensToWithLegacyAllowanceTarget(token, to, amount)
// Revert with the data returned from the transferFrom call.
returndatacopy(0, 0, rdsize)
revert(0, rdsize)
}
}
// Move tokens by going through the legacy allowance target contract.
function moveTakerTokensToWithLegacyAllowanceTarget(token, to, amount) {
mstore(0xB00, ALLOWANCE_TARGET_EXECUTE_CALL_SELECTOR_32)
mstore(0xB04, token)
mstore(0xB24, 0x40)
mstore(0xB44, 0x64)
mstore(0xB64, TRANSFER_FROM_CALL_SELECTOR_32)
mstore(0xB68, caller())
mstore(0xB88, to)
mstore(0xBA8, amount)
if iszero(call(gas(), mload(0xA60), 0, 0xB00, 0xC8, 0x00, 0x0)) {
bubbleRevert()
}
// If this fall back failed, the swap will most likely fail
// so there's no need to validate the result.
}
// Checks if a token possibly belongs to the GREEDY_TOKENS_BLOOM_FILTER
// bloom filter.
function isTokenPossiblyGreedy(token) -> isPossiblyGreedy {
// The hash is given by:
// (1 << (keccak256(token) % 256)) | (1 << (token % 256))
mstore(0, token)
let h := or(shl(mod(keccak256(0, 32), 256), 1), shl(mod(token, 256), 1))
isPossiblyGreedy := eq(and(h, mload(0xA80)), h)
}
}
// Revert if we bought too little.

View File

@@ -0,0 +1,70 @@
// 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 "../libs/LibNativeOrder.sol";
import "../libs/LibSignature.sol";
/// @dev Feature for batch/market filling limit and RFQ orders.
interface IBatchFillNativeOrdersFeature {
/// @dev Fills multiple limit orders.
/// @param orders Array of limit orders.
/// @param signatures Array of signatures corresponding to each order.
/// @param takerTokenFillAmounts Array of desired amounts to fill each order.
/// @param revertIfIncomplete If true, reverts if this function fails to
/// fill the full fill amount for any individual order.
/// @return takerTokenFilledAmounts Array of amounts filled, in taker token.
/// @return makerTokenFilledAmounts Array of amounts filled, in maker token.
function batchFillLimitOrders(
LibNativeOrder.LimitOrder[] calldata orders,
LibSignature.Signature[] calldata signatures,
uint128[] calldata takerTokenFillAmounts,
bool revertIfIncomplete
)
external
payable
returns (
uint128[] memory takerTokenFilledAmounts,
uint128[] memory makerTokenFilledAmounts
);
/// @dev Fills multiple RFQ orders.
/// @param orders Array of RFQ orders.
/// @param signatures Array of signatures corresponding to each order.
/// @param takerTokenFillAmounts Array of desired amounts to fill each order.
/// @param revertIfIncomplete If true, reverts if this function fails to
/// fill the full fill amount for any individual order.
/// @return takerTokenFilledAmounts Array of amounts filled, in taker token.
/// @return makerTokenFilledAmounts Array of amounts filled, in maker token.
function batchFillRfqOrders(
LibNativeOrder.RfqOrder[] calldata orders,
LibSignature.Signature[] calldata signatures,
uint128[] calldata takerTokenFillAmounts,
bool revertIfIncomplete
)
external
returns (
uint128[] memory takerTokenFilledAmounts,
uint128[] memory makerTokenFilledAmounts
);
}

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

@@ -21,7 +21,7 @@ pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./libs/LibSignature.sol";
import "../libs/LibSignature.sol";
/// @dev Meta-transactions feature.
interface IMetaTransactionsFeature {

View File

@@ -0,0 +1,117 @@
// 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";
interface IMultiplexFeature {
// Parameters for `batchFill`.
struct BatchFillData {
// The token being sold.
IERC20TokenV06 inputToken;
// The token being bought.
IERC20TokenV06 outputToken;
// The amount of `inputToken` to sell.
uint256 sellAmount;
// The nested calls to perform.
WrappedBatchCall[] calls;
}
// Represents a call nested within a `batchFill`.
struct WrappedBatchCall {
// The selector of the function to call.
bytes4 selector;
// Amount of `inputToken` to sell.
uint256 sellAmount;
// ABI-encoded parameters needed to perform the call.
bytes data;
}
// Parameters for `multiHopFill`.
struct MultiHopFillData {
// The sell path, i.e.
// tokens = [inputToken, hopToken1, ..., hopTokenN, outputToken]
address[] tokens;
// The amount of `tokens[0]` to sell.
uint256 sellAmount;
// The nested calls to perform.
WrappedMultiHopCall[] calls;
}
// Represents a call nested within a `multiHopFill`.
struct WrappedMultiHopCall {
// The selector of the function to call.
bytes4 selector;
// ABI-encoded parameters needed to perform the call.
bytes data;
}
event LiquidityProviderSwap(
address inputToken,
address outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
address provider,
address recipient
);
event ExpiredRfqOrder(
bytes32 orderHash,
address maker,
uint64 expiry
);
/// @dev Executes a batch of fills selling `fillData.inputToken`
/// for `fillData.outputToken` in sequence. Refer to the
/// internal variant `_batchFill` for the allowed nested
/// operations.
/// @param fillData Encodes the input/output tokens, the sell
/// amount, and the nested operations for this batch fill.
/// @param minBuyAmount The minimum amount of `fillData.outputToken`
/// to buy. Reverts if this amount is not met.
/// @return outputTokenAmount The amount of the output token bought.
function batchFill(
BatchFillData calldata fillData,
uint256 minBuyAmount
)
external
payable
returns (uint256 outputTokenAmount);
/// @dev Executes a sequence of fills "hopping" through the
/// path of tokens given by `fillData.tokens`. Refer to the
/// internal variant `_multiHopFill` for the allowed nested
/// operations.
/// @param fillData Encodes the path of tokens, the sell amount,
/// and the nested operations for this multi-hop fill.
/// @param minBuyAmount The minimum amount of the output token
/// to buy. Reverts if this amount is not met.
/// @return outputTokenAmount The amount of the output token bought.
function multiHopFill(
MultiHopFillData calldata fillData,
uint256 minBuyAmount
)
external
payable
returns (uint256 outputTokenAmount);
}

View File

@@ -0,0 +1,116 @@
// 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 "../libs/LibSignature.sol";
import "../libs/LibNativeOrder.sol";
/// @dev Events emitted by NativeOrdersFeature.
interface INativeOrdersEvents {
/// @dev Emitted whenever a `LimitOrder` is filled.
/// @param orderHash The canonical hash of the order.
/// @param maker The maker of the order.
/// @param taker The taker of the order.
/// @param feeRecipient Fee recipient of the order.
/// @param takerTokenFilledAmount How much taker token was filled.
/// @param makerTokenFilledAmount How much maker token was filled.
/// @param protocolFeePaid How much protocol fee was paid.
/// @param pool The fee pool associated with this order.
event LimitOrderFilled(
bytes32 orderHash,
address maker,
address taker,
address feeRecipient,
address makerToken,
address takerToken,
uint128 takerTokenFilledAmount,
uint128 makerTokenFilledAmount,
uint128 takerTokenFeeFilledAmount,
uint256 protocolFeePaid,
bytes32 pool
);
/// @dev Emitted whenever an `RfqOrder` is filled.
/// @param orderHash The canonical hash of the order.
/// @param maker The maker of the order.
/// @param taker The taker of the order.
/// @param takerTokenFilledAmount How much taker token was filled.
/// @param makerTokenFilledAmount How much maker token was filled.
/// @param pool The fee pool associated with this order.
event RfqOrderFilled(
bytes32 orderHash,
address maker,
address taker,
address makerToken,
address takerToken,
uint128 takerTokenFilledAmount,
uint128 makerTokenFilledAmount,
bytes32 pool
);
/// @dev Emitted whenever a limit or RFQ order is cancelled.
/// @param orderHash The canonical hash of the order.
/// @param maker The order maker.
event OrderCancelled(
bytes32 orderHash,
address maker
);
/// @dev Emitted whenever Limit orders are cancelled by pair by a maker.
/// @param maker The maker of the order.
/// @param makerToken The maker token in a pair for the orders cancelled.
/// @param takerToken The taker token in a pair for the orders cancelled.
/// @param minValidSalt The new minimum valid salt an order with this pair must
/// have.
event PairCancelledLimitOrders(
address maker,
address makerToken,
address takerToken,
uint256 minValidSalt
);
/// @dev Emitted whenever RFQ orders are cancelled by pair by a maker.
/// @param maker The maker of the order.
/// @param makerToken The maker token in a pair for the orders cancelled.
/// @param takerToken The taker token in a pair for the orders cancelled.
/// @param minValidSalt The new minimum valid salt an order with this pair must
/// have.
event PairCancelledRfqOrders(
address maker,
address makerToken,
address takerToken,
uint256 minValidSalt
);
/// @dev Emitted when new addresses are allowed or disallowed to fill
/// orders with a given txOrigin.
/// @param origin The address doing the allowing.
/// @param addrs The address being allowed/disallowed.
/// @param allowed Indicates whether the address should be allowed.
event RfqOrderOriginsAllowed(
address origin,
address[] addrs,
bool allowed
);
}

View File

@@ -21,98 +21,15 @@ pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./libs/LibSignature.sol";
import "./libs/LibNativeOrder.sol";
import "../libs/LibSignature.sol";
import "../libs/LibNativeOrder.sol";
import "./INativeOrdersEvents.sol";
/// @dev Feature for interacting with limit orders.
interface INativeOrdersFeature {
/// @dev Emitted whenever a `LimitOrder` is filled.
/// @param orderHash The canonical hash of the order.
/// @param maker The maker of the order.
/// @param taker The taker of the order.
/// @param feeRecipient Fee recipient of the order.
/// @param takerTokenFilledAmount How much taker token was filled.
/// @param makerTokenFilledAmount How much maker token was filled.
/// @param protocolFeePaid How much protocol fee was paid.
/// @param pool The fee pool associated with this order.
event LimitOrderFilled(
bytes32 orderHash,
address maker,
address taker,
address feeRecipient,
address makerToken,
address takerToken,
uint128 takerTokenFilledAmount,
uint128 makerTokenFilledAmount,
uint128 takerTokenFeeFilledAmount,
uint256 protocolFeePaid,
bytes32 pool
);
/// @dev Emitted whenever an `RfqOrder` is filled.
/// @param orderHash The canonical hash of the order.
/// @param maker The maker of the order.
/// @param taker The taker of the order.
/// @param takerTokenFilledAmount How much taker token was filled.
/// @param makerTokenFilledAmount How much maker token was filled.
/// @param pool The fee pool associated with this order.
event RfqOrderFilled(
bytes32 orderHash,
address maker,
address taker,
address makerToken,
address takerToken,
uint128 takerTokenFilledAmount,
uint128 makerTokenFilledAmount,
bytes32 pool
);
/// @dev Emitted whenever a limit or RFQ order is cancelled.
/// @param orderHash The canonical hash of the order.
/// @param maker The order maker.
event OrderCancelled(
bytes32 orderHash,
address maker
);
/// @dev Emitted whenever Limit orders are cancelled by pair by a maker.
/// @param maker The maker of the order.
/// @param makerToken The maker token in a pair for the orders cancelled.
/// @param takerToken The taker token in a pair for the orders cancelled.
/// @param minValidSalt The new minimum valid salt an order with this pair must
/// have.
event PairCancelledLimitOrders(
address maker,
address makerToken,
address takerToken,
uint256 minValidSalt
);
/// @dev Emitted whenever RFQ orders are cancelled by pair by a maker.
/// @param maker The maker of the order.
/// @param makerToken The maker token in a pair for the orders cancelled.
/// @param takerToken The taker token in a pair for the orders cancelled.
/// @param minValidSalt The new minimum valid salt an order with this pair must
/// have.
event PairCancelledRfqOrders(
address maker,
address makerToken,
address takerToken,
uint256 minValidSalt
);
/// @dev Emitted when new addresses are allowed or disallowed to fill
/// orders with a given txOrigin.
/// @param origin The address doing the allowing.
/// @param addrs The address being allowed/disallowed.
/// @param allowed Indicates whether the address should be allowed.
event RfqOrderOriginsAllowed(
address origin,
address[] addrs,
bool allowed
);
interface INativeOrdersFeature is
INativeOrdersEvents
{
/// @dev Transfers protocol fees from the `FeeCollector` pools into
/// the staking contract.

View File

@@ -0,0 +1,50 @@
// 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";
/// @dev VIP PancakeSwap/BakerySwap/SushiSwap fill functions.
interface IPancakeSwapFeature {
enum ProtocolFork {
PancakeSwap,
BakerySwap,
SushiSwap
}
/// @dev Efficiently sell directly to PancakeSwap/BakerySwap/Sushiswap.
/// @param tokens Sell path.
/// @param sellAmount of `tokens[0]` Amount to sell.
/// @param minBuyAmount Minimum amount of `tokens[-1]` to buy.
/// @param fork The protocol fork to use.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToPancakeSwap(
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
ProtocolFork fork
)
external
payable
returns (uint256 buyAmount);
}

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