Compare commits

...

195 Commits

Author SHA1 Message Date
Jacob Evans
4072724866 Added Call.t.sol 2022-09-09 10:01:28 +10:00
Jacob Evans
74be3d1d96 evm 101 2022-09-08 20:17:06 +10:00
Jacob Evans
730b476987 Make a V6 WETH9 2022-06-17 07:16:23 +10:00
Jacob Evans
84e353aa38 Protocol Academy - Transformers 2022-06-16 20:16:40 +10:00
Michael Zhu
151915ec46 Migration and DeployedFeature tests 2022-06-09 14:33:39 -07:00
Michael Zhu
aa20eaac47 Add FeatureStorage test 2022-06-09 12:06:21 -07:00
Jacob Evans
ba7599ad39 Protocol Academy - Architecture 2022-06-02 20:23:14 +10:00
Michael Zhu
5756d7c563 Pull git submodules in CI 2022-06-01 18:39:07 -07:00
Michael Zhu
2577caaf5a forge install: ../contracts/test/foundry/deps/ds-test 2022-05-19 09:00:05 -07:00
Michael Zhu
603813191f Foundry test skeleton 2022-05-18 15:54:17 -07:00
Michael Zhu
0484519e4d Add typechain to zero-ex 2022-05-18 13:39:22 -07:00
Michael Zhu
275542b6b2 Add foundry.toml to zero-ex directory 2022-05-18 13:36:29 -07:00
Ido Kleinman
f55eaa867b Add BiSwap (as UniV2 clone) on BSC (#471)
* Add BiSwap (as UniV2 clone) on BSC

* changelog PR number

* add BSW

* remove BiSwap from transformer_utils

* Do not initialize BalancerV2SwapInfoCache on unsupported chains [TKR-365] (#472)

* Do not initialize BalancerV2SwapInfoCache on unsupported chains
* Update CHANGELOG.json

* Updated CHANGELOGS & MD docs

* Publish

 - @0x/asset-swapper@16.57.3

* chore: Decomission SnowSwap [TKR-356] (#468)

* Decomission SnowSwap

* SnowSwap doesn't have much liquidity anymore (the largest pool has ~$50k)

* Update CHANGELOG.json

* Update CHANGELOG.json

* chore: Offboard Swerve Finance and LinkSwap [TKR-356] (#469)

* Offboard swerve

* Update CHANGELOG.json

* Offboard LinkSwap

* Remove unused import

* Fix CHANGELOG.json

* chore: Offboard Eth2Dai [TKR-356] (#470)

* Offboard Eth2Dai

* Update CHANGELOG.json

* feat: add IRfqClient (#467)

* add message to changelog for #467 (#474)

* Update saddle mainnet pools (#450)

* Add saddle v2 pools

* remove outdated pools

* add two saddle meta pools

* forgot changelog

* remove saddle metapools

* changelog update

* Fix a lint issue (#475)

* Updated CHANGELOGS & MD docs

* Publish

 - @0x/asset-swapper@16.59.0

* Add BiSwap (as UniV2 clone) on BSC

* rebase new changes for balv2, up changelog, quotes working

* remove Biswap from transformer_utils once again

Co-authored-by: Kyu <kyuhyun217@gmail.com>
Co-authored-by: Github Actions <github-actions@github.com>
Co-authored-by: phil-ociraptor <phil@0x.org>
Co-authored-by: Cece Z <me@cecez.xyz>
Co-authored-by: Noah Khamliche <noah@0xproject.com>
2022-05-16 17:11:23 -07:00
Github Actions
6b2856424a Publish
- @0x/asset-swapper@16.59.0
2022-05-13 00:07:18 +00:00
Github Actions
da757c4700 Updated CHANGELOGS & MD docs 2022-05-13 00:07:16 +00:00
Kyu
75e6654884 Fix a lint issue (#475) 2022-05-12 16:49:10 -07:00
Cece Z
87308e7693 Update saddle mainnet pools (#450)
* Add saddle v2 pools

* remove outdated pools

* add two saddle meta pools

* forgot changelog

* remove saddle metapools

* changelog update
2022-05-12 18:59:55 -04:00
phil-ociraptor
d5eef93a76 add message to changelog for #467 (#474) 2022-05-11 22:17:17 -05:00
phil-ociraptor
a7f23a982e feat: add IRfqClient (#467) 2022-05-11 12:35:05 -05:00
Kyu
9eadc5fc28 chore: Offboard Eth2Dai [TKR-356] (#470)
* Offboard Eth2Dai

* Update CHANGELOG.json
2022-05-10 13:54:28 -07:00
Kyu
92ad1a612e chore: Offboard Swerve Finance and LinkSwap [TKR-356] (#469)
* Offboard swerve

* Update CHANGELOG.json

* Offboard LinkSwap

* Remove unused import

* Fix CHANGELOG.json
2022-05-10 13:13:18 -07:00
Kyu
09413c0e12 chore: Decomission SnowSwap [TKR-356] (#468)
* Decomission SnowSwap

* SnowSwap doesn't have much liquidity anymore (the largest pool has ~$50k)

* Update CHANGELOG.json

* Update CHANGELOG.json
2022-05-10 09:55:43 -07:00
Github Actions
23788b41d5 Publish
- @0x/asset-swapper@16.57.3
2022-05-10 01:41:10 +00:00
Github Actions
ccf999a495 Updated CHANGELOGS & MD docs 2022-05-10 01:41:06 +00:00
Kyu
aa1016ee5f Do not initialize BalancerV2SwapInfoCache on unsupported chains [TKR-365] (#472)
* Do not initialize BalancerV2SwapInfoCache on unsupported chains
* Update CHANGELOG.json
2022-05-09 18:21:04 -07:00
Github Actions
423ef57344 Publish
- @0x/asset-swapper@16.57.2
2022-05-02 21:22:37 +00:00
Github Actions
c18149e82f Updated CHANGELOGS & MD docs 2022-05-02 21:22:33 +00:00
Jorge Pérez
d14aebf724 Fix the filter for considered sources on indicative sells for Quote Report (#466) 2022-05-02 15:45:15 -05:00
Kyu
ba719a9631 Add cvxfxs-fxs curve pool on Ethereum mainnet (#465)
* Add cvxfxs-fxs curve pool on Ethereum mainnet

* Update CHANGELOG.json

* Fix an existing formatting issue

* Adjust gasSchedule and merge the change under 16.57.1
2022-04-27 17:07:36 -07:00
eobbad
d36034d958 chore/ANY-QUICK on polygon MAG-MIM on avax (#464)
* Added ANY/QUICK pair on Polygon

* Updated changelog.json

* Update CHANGELOG.json
2022-04-26 10:55:03 -04:00
Github Actions
7750c57620 Publish
- @0x/contracts-erc20@3.3.29
 - @0x/contracts-test-utils@5.4.20
 - @0x/contracts-treasury@1.4.12
 - @0x/contracts-utils@4.8.10
 - @0x/contracts-zero-ex@0.32.0
 - @0x/asset-swapper@16.57.0
 - @0x/contract-addresses@6.13.0
 - @0x/contract-wrappers@13.20.1
 - @0x/migrations@8.1.18
 - @0x/protocol-utils@11.12.0
2022-04-22 07:05:10 +00:00
Github Actions
4d027e11d1 Updated CHANGELOGS & MD docs 2022-04-22 07:05:06 +00:00
Lawrence Forman
470e9a4697 AS: Balancer V2 batchSwap (#462)
* Draft. PoC pseudo code showing general idea for resuing SOR path creation logic and adding multihop support.

* Add actual Balancer SDK function calls.

* Update to handle buys.

* Correct taker>maker for buy.

* Draft. PoC pseudo code showing general idea for resuing SOR path creation logic and adding multihop support.

* make it build

* rebase

* add BalancerV2Batch protocol

* add BalancerV2Batch protocol

* get balancer v2 multihop working

* fix BalancerV2Batch for sells (buys still iffy)

* fix buys, appease linter and prettier

* remove unused RPC URL from balancer sdk construction

* update changelogs

* clean up comments
add event loop yield in `BalancerV2SwapInfoCache.loadTopPools()`

* add negative result check on balancerv2batch swap output

* compiler hack

* reintroduce CompilerHack

* delete unused multibridge sampler

* remove compilerhack

* reintroduce compilerhack

* try to fix CI compile errors

* plz work

* plz work

* pretty plz work

* yay it works, also address feedback

* appease linter

* deploy new FQTs

Co-authored-by: johngrantuk <johngrantuk@googlemail.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2022-04-22 02:43:41 -04:00
Github Actions
7c51412e2f Publish
- @0x/asset-swapper@16.56.0
2022-04-21 21:16:27 +00:00
Github Actions
b3d1f3cd10 Updated CHANGELOGS & MD docs 2022-04-21 21:16:23 +00:00
mzhu25
389bb77439 Add estimatedGas to ExtendedQuoteReport (#463) 2022-04-21 13:52:13 -07:00
Github Actions
4327885a00 Publish
- @0x/asset-swapper@16.55.0
2022-04-07 16:07:52 +00:00
Github Actions
0aef0afbbb Updated CHANGELOGS & MD docs 2022-04-07 16:07:49 +00:00
Lawrence Forman
fa4c3a4f5f fix quote consumer RFQ VIP code path not checking if transfromERC20 is required (#461)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2022-04-07 11:58:07 -04:00
Github Actions
1d7c527c5c Publish
- @0x/asset-swapper@16.54.0
2022-04-06 03:26:22 +00:00
Github Actions
cbe3135e4b Updated CHANGELOGS & MD docs 2022-04-06 03:26:18 +00:00
Lawrence Forman
955ad49711 add real VIP support for eligible RFQT swaps (#458)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2022-04-05 23:00:12 -04:00
Github Actions
8d6f6e76e0 Publish
- @0x/contracts-erc20@3.3.28
 - @0x/contracts-test-utils@5.4.19
 - @0x/contracts-treasury@1.4.11
 - @0x/contracts-utils@4.8.9
 - @0x/contracts-zero-ex@0.31.2
 - @0x/asset-swapper@16.53.0
 - @0x/contract-addresses@6.12.1
 - @0x/contract-artifacts@3.18.0
 - @0x/contract-wrappers@13.20.0
 - @0x/migrations@8.1.17
 - @0x/protocol-utils@1.11.2
2022-03-31 15:09:24 +00:00
Github Actions
9337115650 Updated CHANGELOGS & MD docs 2022-03-31 15:09:21 +00:00
Kim Persson
fa45a44fe4 fix: use Node 16 for publish GH action (#457) 2022-03-31 16:47:02 +02:00
Kim Persson
c9c7ac8559 feat: add block number to quote report data [TKR-314] (#448)
* feat: add blockNumber to MarketSideLiquidity response

* fix: return block number back in swap quote response

* chore: add asset-swapper changelog entry
2022-03-31 15:42:34 +02:00
Kim Persson
c881723578 feat: use neon-router in CI tests (#453)
* fix: initially skip all tests that don't work with the Rust router

* fix: enable rust router for CircleCI tests

* fix: handle invalid output sampels & enable numSamples tests

* chore: add comments about disabled tests

* chore: add asset-swapper changelog entry
2022-03-31 14:32:59 +02:00
Kim Persson
c9c30d3a76 chore: bump ts version to solve type issue with ethereumjs (#455) 2022-03-31 13:55:17 +02:00
Noah Khamliche
73dfdb5b69 fixed gas estimation and removed hint from intermediate tokens 2022-03-21 14:51:23 -04:00
Noah Khamliche
e638268f94 updated routing 2022-03-21 14:51:23 -04:00
Noah Khamliche
0bfd765481 updating changelog 2022-03-21 14:51:23 -04:00
Noah Khamliche
1f12893735 fixing routing 2022-03-21 14:51:23 -04:00
Noah Khamliche
dd3d9337c4 Added Stargate curve pool 2022-03-21 14:51:23 -04:00
Lawrence Forman
904214f4a8 ugprade tools deps and regenerate wrappers (#449)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2022-03-16 12:14:31 -04:00
Noah Khamliche
64c090c4b4 removed local bignumber resolution 2022-03-10 21:22:28 -05:00
Noah Khamliche
e24474f152 lint and prettier 2022-03-10 21:22:28 -05:00
Noah Khamliche
29fa408256 final nitpicks 2022-03-10 21:22:28 -05:00
Noah Khamliche
1b94cc68af fixed gas schedule 2022-03-10 21:22:28 -05:00
Noah Khamliche
f5b4bb3035 removed low liquidity pools, and fixed some routing 2022-03-10 21:22:28 -05:00
Noah Khamliche
afd880f28c poolAddress -> NULL_ADDRESS for consitent types 2022-03-10 21:22:28 -05:00
Noah Khamliche
cd14cdd168 fixed lint 2022-03-10 21:22:28 -05:00
Noah Khamliche
c8ff53a75f fixed mobius common argument abstraction 2022-03-10 21:22:28 -05:00
Noah Khamliche
6d08add20b minimized reused code for mobius pairs 2022-03-10 21:22:28 -05:00
Noah Khamliche
29f9c725e3 bump changelog to version after feat/BTRFLYCurve 2022-03-10 21:22:28 -05:00
Noah Khamliche
a83453f07f prettier and lint 2022-03-10 21:22:28 -05:00
Noah Khamliche
ae365ce92c finished off mobius money pairs 2022-03-10 21:22:28 -05:00
Noah Khamliche
77a592e891 added mobius config for celo and some inital test pools 2022-03-10 21:22:28 -05:00
Github Actions
9a1df67d6b Publish
- @0x/asset-swapper@16.51.0
2022-03-10 04:58:07 +00:00
Github Actions
4b91411faf Updated CHANGELOGS & MD docs 2022-03-10 04:58:04 +00:00
Jacob Evans
622a542d57 feat: Curve YFI-ETH (#444)
* feat: Curve YFI-ETH

* CHANGELOG
2022-03-10 14:36:59 +10:00
Github Actions
cba53a9a50 Publish
- @0x/asset-swapper@16.50.3
2022-03-09 14:59:25 +00:00
Github Actions
e186f27f63 Updated CHANGELOGS & MD docs 2022-03-09 14:59:22 +00:00
Kim Persson
4cd767ecb8 feat: VIP routing in the router, don't create fallback orders for native [TKR-243] (#440)
* feat: calculate all routes and VIP only routes in a single router call

* fix: Try to disable using fallback orders for quotes with native orders

* fix: create VIP sources set once per routing call

* chore: use private publish version of neon-router to test

* chore(lint): comment out unused fn _addOptionalFallbackAsync

* chore: update to latest private publish of neon-router

* refactor: fix router metrics beforeTimeMs naming

* feat: don't recompute isVip for ever sample of a source

* chore: update neon-router to real published version

* fix: merge conflict resolution issue

* chore: add asset-swapper changelog entry
2022-03-09 15:39:47 +01:00
Shawn
f6e85aedf1 Fix/routing glue optimization (#439)
* fix: only create fills if using js router, remove `unoptimizedPath`

* minor optimizations

* remove the cap of route output in buys

* change PR number

* fix: Update Ropsten UniswapV3 Router address (#441)

* fix: Update Ropsten UniswapV3 Router address

* Update CHANGELOG

* Updated CHANGELOGS & MD docs

* Publish

 - @0x/asset-swapper@16.50.2

* change PR number

Co-authored-by: Kim Persson <kimpersson88@gmail.com>
Co-authored-by: Jacob Evans <jacob@dekz.net>
Co-authored-by: Github Actions <github-actions@github.com>
2022-03-08 16:26:22 -08:00
Github Actions
b3ee294ba5 Publish
- @0x/asset-swapper@16.50.2
2022-03-07 01:37:11 +00:00
Github Actions
1c242def93 Updated CHANGELOGS & MD docs 2022-03-07 01:37:07 +00:00
Jacob Evans
f0fe6f2f69 fix: Update Ropsten UniswapV3 Router address (#441)
* fix: Update Ropsten UniswapV3 Router address

* Update CHANGELOG
2022-03-07 11:18:25 +10:00
Github Actions
f86d555e49 Publish
- @0x/asset-swapper@16.50.1
2022-03-03 13:04:04 +00:00
Github Actions
b0f2c40463 Updated CHANGELOGS & MD docs 2022-03-03 13:04:00 +00:00
Kim Persson
87be6fbb8a fix: lower UniswapV3Sampler quote gas allowance to 700k (#438)
* fix: lower UniswapV3Sampler quote gas allowance to 700k

* chore: add asset-swapper changelog entry
2022-03-03 13:45:20 +01:00
Noah Khamliche
9141a9d2c8 feat: BTRFLY/WETH factory pool (#437)
* added curve support for BTRFLY/WETH factory pool

* prettier and lint

* remove timestamp

* fixed gas schedule for btrflyweth pool

* chore: update Node16 (#384)


* Node 16

* update yarn.lock

* Update ganache-cli and merkle-patricia-tree

* [TKR-275] Add Geist on Fantom (#398)

* Add Geist on Fantom

* nvm there is not subgraph for it

* finish giest utils

* Address pr comments

* lowercase gtoken addresses

* return undefined instead of error for unsupported pairs

* another lower case

* Update fantom fillQuoteTransformer address

* more const clean up

* feat: Improve Uniswap V3 gas schedule redux (#424)

* Revert "fix: Revert Improve Uniswap V3 gas schedule (#397) (#419)"

This reverts commit df0e0866e4.

* fix: UniswapV3Sampler return token amounts as the last value in return tuple

* fix: bump Uniswap V3 quote max gas because QuoterV2 is more expensive

* fix: don't try to rout 0 sellAmount/buyAmount quotes

* fix: Linting issue

* fix: use median gas usage instead of mean in UniV3 gas schedule

* chore: add asset-swapper changelog entry

* fix: remove contract-addresses changelog empty row failing linting

* Updated CHANGELOGS & MD docs

* Publish

 - @0x/contracts-erc20@3.3.27
 - @0x/contracts-test-utils@5.4.18
 - @0x/contracts-treasury@1.4.10
 - @0x/contracts-utils@4.8.8
 - @0x/contracts-zero-ex@0.31.1
 - @0x/asset-swapper@16.50.0
 - @0x/contract-addresses@6.12.0
 - @0x/contract-wrappers@13.19.1
 - @0x/migrations@8.1.16
 - @0x/protocol-utils@1.11.1

* Add v4 NFT Audits (#435)

* prettier and lint

Co-authored-by: Jacob Evans <jacob@dekz.net>
Co-authored-by: Cece Z <cece@0xproject.com>
Co-authored-by: Kim Persson <kimpers@users.noreply.github.com>
Co-authored-by: Github Actions <github-actions@github.com>
Co-authored-by: Jessica Lin <jlin2700@gmail.com>
2022-03-02 21:18:40 -05:00
Jessica Lin
7f75de347e Add v4 NFT Audits (#435) 2022-03-02 10:46:00 -08:00
Github Actions
329f7761c3 Publish
- @0x/contracts-erc20@3.3.27
 - @0x/contracts-test-utils@5.4.18
 - @0x/contracts-treasury@1.4.10
 - @0x/contracts-utils@4.8.8
 - @0x/contracts-zero-ex@0.31.1
 - @0x/asset-swapper@16.50.0
 - @0x/contract-addresses@6.12.0
 - @0x/contract-wrappers@13.19.1
 - @0x/migrations@8.1.16
 - @0x/protocol-utils@1.11.1
2022-03-02 12:55:58 +00:00
Github Actions
0d8e83cd75 Updated CHANGELOGS & MD docs 2022-03-02 12:55:55 +00:00
Kim Persson
e5d60b8077 feat: Improve Uniswap V3 gas schedule redux (#424)
* Revert "fix: Revert Improve Uniswap V3 gas schedule (#397) (#419)"

This reverts commit df0e0866e4.

* fix: UniswapV3Sampler return token amounts as the last value in return tuple

* fix: bump Uniswap V3 quote max gas because QuoterV2 is more expensive

* fix: don't try to rout 0 sellAmount/buyAmount quotes

* fix: Linting issue

* fix: use median gas usage instead of mean in UniV3 gas schedule

* chore: add asset-swapper changelog entry

* fix: remove contract-addresses changelog empty row failing linting
2022-03-02 13:36:12 +01:00
Cece Z
ae2fe55efa [TKR-275] Add Geist on Fantom (#398)
* Add Geist on Fantom

* nvm there is not subgraph for it

* finish giest utils

* Address pr comments

* lowercase gtoken addresses

* return undefined instead of error for unsupported pairs

* another lower case

* Update fantom fillQuoteTransformer address

* more const clean up
2022-03-02 01:34:30 -05:00
Jacob Evans
6073607d3e chore: update Node16 (#384)
* Node 16

* update yarn.lock

* Update ganache-cli and merkle-patricia-tree
2022-03-02 11:50:35 +10:00
Github Actions
389ebb5df8 Publish
- @0x/asset-swapper@16.49.9
2022-02-24 09:52:41 +00:00
Github Actions
fd9655e9d4 Updated CHANGELOGS & MD docs 2022-02-24 09:52:38 +00:00
Kim Persson
6480aaa189 fix: native order scaling & don't try to route 1 wei trades (it will fail) (#430)
* feat: scale oversized native orders to quote amount for fake samples

* chore: temporarily use private publish neon-router version

* fix: short circuit 1 base unit trades to avoid router error

* chore: use published version of `neon-router`

* chore: add changelog entry for asset-swapper
2022-02-24 10:34:17 +01:00
Github Actions
38969bb0a8 Publish
- @0x/contracts-erc20@3.3.26
 - @0x/contracts-test-utils@5.4.17
 - @0x/contracts-treasury@1.4.9
 - @0x/contracts-utils@4.8.7
 - @0x/contracts-zero-ex@0.31.0
 - @0x/asset-swapper@16.49.8
 - @0x/contract-artifacts@3.17.0
 - @0x/contract-wrappers@13.19.0
 - @0x/migrations@8.1.15
 - @0x/protocol-utils@1.11.0
2022-02-22 22:32:24 +00:00
Github Actions
1847ab93af Updated CHANGELOGS & MD docs 2022-02-22 22:32:20 +00:00
mzhu25
c1177416f5 [Final] ERC721 and ERC1155 Orders (#429)
* add LibERC721Order.sol

* Add ERC721 interface to vendor/

* Add ERC721OrdersFeature interface

* Storage lib for ERC721 orders feature

* Implement basic functionality for ERC721 orders (buy, sell, cancel, etc)

* Add isValidERC721OrderSignature to interface

* implement onERC721Received

* Implement batchBuyERC721s

* left/right orders -> sell/buy orders

* Add missing @return comments

* Implement matching functions

* Use SafeMath where necessary

* add rich errors for ERC721OrdersFeature

* Add comments

* Add presign support for ERC721 orders

* Cancel using just the order nonce

* Add IERC721OrdersFeature to IZeroEx

* Add taker callback

* Assembly optimizations in LibERC721Order

* Add ERC721Orders TS class

* create zero-ex/contracts/test/integration/ and tokens/ directories

* TestMintableERC721Token

* tmp

* address feedback from original PR (#391)

* address feedback from original PR

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

Co-authored-by: Kim Persson <kimpers@users.noreply.github.com>

* address review feedback and improve order parameter naming

* Add batchCancel function

* Emit order fields in preSign

* Fix tests

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Kim Persson <kimpers@users.noreply.github.com>
Co-authored-by: Michael Zhu <mchl.zhu.96@gmail.com>

* Remove revertIfIncomplete from batchMatch

* Sanity check maker address in preSign

* ERC1155OrdersFeature contracts

* Commence refactor, abstract base contract

* ERC721OrdersFeature inherits from NFTOrders

* Refactor ERC1155OrdersFeature to inherit from NFTOrders

* Fix order hashing

* Fix ERC721OrdersFeature tests

* Typos

* Remove maker address from preSigned mapping

* disable dex sampler tests

* Refactor TS tooling

* Address PR feedback

* Rearrange event fields to better align with struct fields

* Update comments

* update AbiEncoder.create params

* Add ERC1155Order to protocol-utils

* Add ERC1155OrdersFeeature tests

* Bump package versions and regenerate contract wrappers

* Add ERC165Feature

* NFT orders: address audit findings (#417)

* CVF-1: use pragma solidity ^0.6 instead of ^0.6.5

* CVF-11: fix inaccurate comment

* CVF-16: Enable taker callbacks for batchBuyERC1155s

* CVF-17: use internal call if revertIfIncomplete is true

* CVF-21: avoid duplicate SLOAD

* CVF-23: merge if statements

* CVF-24: Reorder status checks to be consistent with ERC721OrdersFeature

* CVF-25: Update unclear comment (canonical hash -> EIP-712 hash)

* CVF-31: Document keys of orderState mapping

* CVF-45: DRY up fees/properties hashing

* CVF-47, CVF-50, CVF-57: calculate properties.length once; hash propertyStructHashArray in-place using assembly

* CVF-56: More descriptive names for assembly variables

* CVF-71: Update confusing comment about rounding in _payFees

* CVF-72: Move ETH assertions outside of loop in _payFees

* CVF-74: Move property validation loop to else branch

* CVF-82: Update inaccurate comment

* CVF-86: Enable taker callbacks for batchBuyERC721s

* CVF-87: use internal call if revertIfIncomplete is true

* CVF-89: Perform token mismatch checks before stateful operations

* CVF-90, CVF-91: Defer ERC20 token mismatch check

* CVF-93: Add inline comments for _payFees parameters in matchERC721Orders

* CVF-94: Fix comment (Step 7 -> Step 5)

* CVF-98: Use binary & operator instead of mod

* CVF-99: Update unclear comment (canonical hash -> EIP-712 hash)

* CVF-65, CVF-66, CVF-67: Copy params.ethAvailable into local variable; check that ethSpent does not exceed ethAvailable; remove ethAvailable < erc20FillAmount check

* CVF-52, CVF-55, CVF-59: calculate fees.length once; hash feeStructHashArray in-place using assembly

* CVF-14, CVF-32: OrderState struct; separate storage mapping for 1155 cancellations so orders can be cancelled by nonce

* Update changelogs, IZeroEx artifact/wrapper

Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Kim Persson <kimpers@users.noreply.github.com>
2022-02-22 10:00:22 -08:00
Github Actions
4fdd203211 Publish
- @0x/asset-swapper@16.49.7
2022-02-22 12:50:50 +00:00
Github Actions
4bc11776d7 Updated CHANGELOGS & MD docs 2022-02-22 12:50:47 +00:00
Kim Persson
eb12eac5f3 fix: start native orders "samples" at 0 & don't skip neg adj orders (#425)
* fix: start native orders "samples" at 0 & don't skip neg adj orders

* fix: bail on routes with invalid output estimation (no valid route)

* chore: bump neon-router version

* chore: add asset-swapper changelog entry
2022-02-22 13:31:47 +01:00
Github Actions
5f5b951998 Publish
- @0x/asset-swapper@16.49.6
2022-02-17 16:02:38 +00:00
Github Actions
8e90547604 Updated CHANGELOGS & MD docs 2022-02-17 16:02:34 +00:00
Noah Khamliche
fbea74d7ff remove comments 2022-02-17 10:40:59 -05:00
Noah Khamliche
dcea16bc13 removed ohmv2/dai and ohmv2/weth, routing is the same without the search overhead 2022-02-17 10:40:59 -05:00
Noah Khamliche
d59a074bd7 updated changelog 2022-02-17 10:40:59 -05:00
Noah Khamliche
39cc4f4dbf fixed btrfly routing to include the ohmV2/dai, ohmV2/btfly, and ohmV2/weth pools 2022-02-17 10:40:59 -05:00
Github Actions
85bcf87af8 Publish
- @0x/asset-swapper@16.49.5
2022-02-14 13:12:38 +00:00
Github Actions
a0fe1c610f Updated CHANGELOGS & MD docs 2022-02-14 13:12:35 +00:00
Kim Persson
5d21af1a0a fix: 1 base unit output amount being scale down, rounding to 0 output (#422)
* fix: 1 base unit output amount being scale down, rounding to 0 output

* chore: add asset-swapper changelog entry

* fix: round scaled output to base units before clamping
2022-02-14 13:54:53 +01:00
Jacob Evans
f6edbd210c Update protocol docs (#421)
* Update protocol docs

* Added functions

* fix table

* eligbility section?

* Trader.xyz shoutout

* Up to
2022-02-11 22:53:49 +10:00
Github Actions
e084807a8f Publish
- @0x/asset-swapper@16.49.4
2022-02-10 15:34:41 +00:00
Github Actions
1c7d512829 Updated CHANGELOGS & MD docs 2022-02-10 15:34:38 +00:00
Kim Persson
df0e0866e4 fix: Revert Improve Uniswap V3 gas schedule (#397) (#419)
* Revert "feat: Improve Uniswap V3 gas schedule (#397)"

This reverts commit 84e4819e6e.

* chore: Add changelog entry
2022-02-10 16:15:54 +01:00
Github Actions
9e6efc3676 Publish
- @0x/asset-swapper@16.49.3
2022-02-10 12:12:08 +00:00
Github Actions
3aef29dace Updated CHANGELOGS & MD docs 2022-02-10 12:12:05 +00:00
Kim Persson
9a16e00577 fix: router RFQ underutilization (#413)
* fix: pass EP overhead to Path & use path comparison all & vip routes

* chore: add changelog entry for asset-swapper
2022-02-10 12:55:30 +01:00
Kim Persson
84e4819e6e feat: Improve Uniswap V3 gas schedule (#397)
* feat: UniswapV3Sampler use QuoterV2 for sells WIP

* feat: UniswapV3Sampler for QuoterV2 buys WIP

* refactor: separate logic to remove stack too deep issue

* feat: Use initializedTicksCrossed from Uniswap QuoterV2 for gas est.

* fix: use Quoter gasUsed instead of estimating gas from pools + ticks

* refactor: clean up UniswapV3Sampler & remove old Quoter interface

* refactor: unify code for buys and sells while handling stack too deep

* fix: use mean gas price from all sample estimating UniV3 gas schedule

* fix: fallback to legacy Uniswap V3 gas estimate if we can't get gasUsed

* refactor: use named function instead of fat arrow

* chore: add asset-swapper changelog entry
2022-02-10 11:16:24 +01:00
Kim Persson
25dd6bc79a fix: incorrect output scaling when input is less than desired amount (#401)
* fix: incorrect output scaling when input is less than desired amount

* chore: bump fast-abi

* chore: add changelog entry for asset-swapper
2022-02-10 10:43:44 +01:00
Jacob Evans
5d2cdb00c2 fix: slippage inconsistency when recalculated in exchange proxy quote consumer (#412)
* fix: Pass slippage down rather than recalculate due to accuracy

* CHANGELOG
2022-02-04 10:37:38 +10:00
Github Actions
0f701f42d3 Publish
- @0x/asset-swapper@16.49.2
2022-01-31 18:24:47 +00:00
Github Actions
3e3e82d3f7 Updated CHANGELOGS & MD docs 2022-01-31 18:24:44 +00:00
Lawrence Forman
c57bf86273 Fix ABI encoding error with two hop buys due to applying slippage to uint(-1) values (#410)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2022-01-31 12:51:17 -05:00
Github Actions
f470d282ee Publish
- @0x/asset-swapper@16.49.1
2022-01-31 07:20:03 +00:00
Github Actions
b8a2526da5 Updated CHANGELOGS & MD docs 2022-01-31 07:19:59 +00:00
Jacob Evans
97575bbde9 fix: worstCaseQuoteInfo calculating buys incorrectly [TKR-296] (#402)
* fix: WorstCaseQuoteInfo buy encoding

* CHANGELOG
2022-01-31 17:01:17 +10:00
Github Actions
e5ed8b2c81 Publish
- @0x/asset-swapper@16.49.0
2022-01-28 22:11:46 +00:00
Github Actions
61fbae3ae2 Updated CHANGELOGS & MD docs 2022-01-28 22:11:42 +00:00
Shawn
5c2255c841 feat: add curve pools (#409)
* feat: Additional Curve pools

* more pools

* fix the format

* changlog

* lowercase address

Co-authored-by: Jacob Evans <jacob@dekz.net>
2022-01-28 12:08:28 -08:00
Github Actions
e036dee6c5 Publish
- @0x/asset-swapper@16.48.0
2022-01-25 22:00:25 +00:00
Github Actions
8583aab241 Updated CHANGELOGS & MD docs 2022-01-25 22:00:21 +00:00
Jacob Evans
5d05b62821 chore: Use MIM on Fantom as an intermediary asset (#405) 2022-01-26 07:42:29 +10:00
Github Actions
0063e8178f Publish
- @0x/asset-swapper@16.47.0
2022-01-25 18:51:07 +00:00
Github Actions
ec6e5dd517 Updated CHANGELOGS & MD docs 2022-01-25 18:51:04 +00:00
Noah Khamliche
9d08fefa1c Feat/synapse (#400)
* added synapse support
2022-01-25 13:21:07 -05:00
Github Actions
2fdca24d4e Publish
- @0x/asset-swapper@16.46.0
2022-01-11 01:10:02 +00:00
Github Actions
42ec0b144e Updated CHANGELOGS & MD docs 2022-01-11 01:09:58 +00:00
Jacob Evans
3f6ce78b46 chore: Enable Curve ETH/CVX (#394)
* chore: Enable Curve ETH/CVX

* pr number
2022-01-11 09:32:07 +10:00
Github Actions
c1300c1068 Publish
- @0x/asset-swapper@16.45.2
2022-01-10 15:09:26 +00:00
Github Actions
9a641cfab6 Updated CHANGELOGS & MD docs 2022-01-10 15:09:23 +00:00
Kim Persson
60345d4465 fix: don't create fills for 0 output samples and negative adjusted rate orders (#387)
* fix: don't try to create fills for 0 output samples

* fix: negative adjusted output native orders causing undefined fills

* fix: make sure to use the same sourcePathId for fills from same source

* fix: should be same sourcePathId within the same DexSample[]

* fix: split native orders into 13 samples to align with interpolation

* chore: add changelog entry for asset-swapper
2022-01-10 14:55:03 +01:00
Github Actions
11dfea47a6 Publish
- @0x/asset-swapper@16.45.1
2022-01-05 05:08:43 +00:00
Github Actions
55e9dd39a2 Updated CHANGELOGS & MD docs 2022-01-05 05:08:41 +00:00
Jacob Evans
1993929bed chore: Celo Update certain tokens since Optics v2 (#390)
* chore: Celo Update certain tokens since Optics v2

* Changelog
2022-01-05 14:44:29 +10:00
Oskar Paolini
e1d81de517 fixes axios object dumping in logs (#345) 2022-01-05 09:46:01 +10:00
Github Actions
a6b3a21635 Publish
- @0x/asset-swapper@16.45.0
2022-01-04 15:00:16 +00:00
Github Actions
fd59cdc2db Updated CHANGELOGS & MD docs 2022-01-04 15:00:13 +00:00
Jacob Evans
98e11b5189 feat: Capture Routing timing metrics (#388) 2022-01-04 15:42:14 +01:00
Github Actions
3bebc7cd62 Publish
- @0x/asset-swapper@16.44.0
2021-12-29 11:45:33 +00:00
Github Actions
56dab6ae8c Updated CHANGELOGS & MD docs 2021-12-29 11:45:30 +00:00
Kim Persson
285f98e9e9 feat: Udate neon-router and use router estimated output amount (#354)
* feat: use Rust router estimated output amount when possible

* fix: use strings for sample ids, and increase samples in the rust router

* fix: remove unnecessary interpolation of out of range values

* fix: don't recalculate sampled dist sum in a loop

* fix: use 14 samples for rust router to work around interpolation issues

* fix: unintentional logic change

* fix: remove local dev plotting param from route fn call

* feat: make neon-router number of samples configurable

* chore: bump to newly published neon-router version

* fix: handle insufficient liquidity at all requested sources

* chore: update asset-swapper changelog
2021-12-29 12:08:24 +01:00
Github Actions
8ae9f59f20 Publish
- @0x/contracts-erc20@3.3.25
 - @0x/contracts-test-utils@5.4.16
 - @0x/contracts-treasury@1.4.8
 - @0x/contracts-utils@4.8.6
 - @0x/contracts-zero-ex@0.30.1
 - @0x/asset-swapper@16.43.0
 - @0x/contract-addresses@6.11.0
 - @0x/contract-wrappers@13.18.5
 - @0x/migrations@8.1.14
 - @0x/protocol-utils@1.10.1
2021-12-24 16:45:24 +00:00
Github Actions
4c341c5ca3 Updated CHANGELOGS & MD docs 2021-12-24 16:45:21 +00:00
Shawn
a3c912c2af feat/optimism [TKR-280] (#385)
* rebase and remove WIP Clipper new weth router test

* remove clipper test

* restore from clipper test

* add uniswapV3 on optimism

* modify token addresses and add EP-related addresses on optimism

* prettier

* modify CHANGLOG.json

* convert addresses to lowercase

* remove testnet addresses

Co-authored-by: Romain Butteaud <romain.butteaud@gmail.com>
2021-12-24 08:28:06 -08:00
Github Actions
5e72eb9af9 Publish
- @0x/asset-swapper@16.42.0
2021-12-21 22:02:45 +00:00
Github Actions
9b08b73c06 Updated CHANGELOGS & MD docs 2021-12-21 22:02:41 +00:00
Jacob Evans
76c7eb7c3e fix: Beethovenx graphql endpoint (#383) 2021-12-22 07:44:25 +10:00
Jacob Evans
9b2e5a3adb fix: PR number in CHANGELOG 2021-12-22 08:11:28 +11:00
Jacob Evans
813d703d12 feat: UniswapV3 on Polygon (#382) 2021-12-22 07:10:21 +10:00
Github Actions
83005d0f3d Publish
- @0x/asset-swapper@16.41.0
2021-12-06 21:48:27 +00:00
Github Actions
d07ffd2688 Updated CHANGELOGS & MD docs 2021-12-06 21:48:24 +00:00
Noah Khamliche
4170f970d0 Sushi router celo fix (#376)
* Updated Sushiswap router on CELO 

Sushi address in the docs was incorrect, this is the correct address `0x1421bDe4B10e8dd459b3BCb598810B1337D56842`.

* address to lowercase

* Update CHANGELOG.json

* fixed sushi router address, replaced celo ref with wcelo, fixed mcusd address

* celo->wcelo

* Update packages/asset-swapper/CHANGELOG.json

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

* changelog

* version bump

Co-authored-by: Jacob Evans <jacob@dekz.net>
2021-12-06 13:31:45 -08:00
Github Actions
dcde12dd70 Publish
- @0x/contracts-erc20@3.3.24
 - @0x/contracts-test-utils@5.4.15
 - @0x/contracts-treasury@1.4.7
 - @0x/contracts-utils@4.8.5
 - @0x/contracts-zero-ex@0.30.0
 - @0x/asset-swapper@16.40.0
 - @0x/contract-addresses@6.10.0
 - @0x/contract-wrappers@13.18.4
 - @0x/migrations@8.1.13
 - @0x/protocol-utils@1.10.0
2021-12-01 20:22:43 +00:00
Github Actions
84a60ec982 Updated CHANGELOGS & MD docs 2021-12-01 20:22:39 +00:00
Kim Persson
9615570dc6 feat: deploy interest tokens (#321)
* feat: Aave aToken deposit/withdrawal [TKR-111] (#293)

* feat: AaveV2 deposit/withdrawal integration WIP

* feat: add basic Aave Reserves cache with data from subgraphs WIP

* feat: hook up Aave Reserves integration

* fix: set allowance before trade & use ERC20 token interface

* refactor: pass aToken to mixin to avoid lookup

* fix: migrate from swap/revert to normal sampling

* fix: Aave gas estimate & refactor to clean up code

* feat: Create a sampler no operation type and make AaveV2Sampler a no-op

* fix: Clipper merge conflict resolution issues

* fix: don't fetch unnecessary Aave pool data & clean up code

* chore: Add changelog entries

* feat: cToken deposit/withdrawal [TKR-222] (#294)

* feat: first stab at a CompoundSampler implementation

* feat: MixinCompound implementation WIP

* feat: Compound integration with cache WIP

* fix: decimals scaling in CompoundSampler

* feat: handle minting and redeeming of cETH

* fix: adjust Compound gas schedule

* refactor: clean up code and add comments in cToken cache

* fix: MixinCompound check allowance on WETH withdrawal & fix indentation

* fix: address review comments and clean up code

* chore: add changelog entries

* feat: enable AaveV2 on Avalanche

* chore: add freshly deployed FQT on Polygon, Avalanche

* fix: temporarily disable on Ethereum mainnet until we redeploy EP

* fix: address PR comments and update changelogs

* fix: correct contract-addresses changelog note
2021-12-01 17:10:22 +01:00
Jacob Evans
880a9c3da0 chore: Curve added ETH/CRV pool (#378) 2021-12-01 14:51:47 +10:00
Jacob Evans
c44bd9d42d Revert "chore: Curve added ETH/CRV pool"
This reverts commit 90b441330b.
2021-12-01 14:19:49 +10:00
Jacob Evans
90b441330b chore: Curve added ETH/CRV pool 2021-12-01 14:17:40 +10:00
Github Actions
e12ed1eddf Publish
- @0x/asset-swapper@16.38.0
2021-11-29 23:23:57 +00:00
Github Actions
ac94023ab3 Updated CHANGELOGS & MD docs 2021-11-29 23:23:54 +00:00
Jacob Evans
281e6acca5 chore: Add ability to capture sampler metrics (#374)
* chore: Add ability to capture sampler metrics

* Added block number metrics
2021-11-30 09:06:05 +10:00
Github Actions
2f1b520409 Publish
- @0x/asset-swapper@16.37.0
2021-11-19 19:15:43 +00:00
Github Actions
21b4eb3d26 Updated CHANGELOGS & MD docs 2021-11-19 19:15:40 +00:00
Noah Khamliche
644f6c7d28 removed comma 2021-11-19 13:46:57 -05:00
Noah Khamliche
0647b9e4f8 Update CHANGELOG.json 2021-11-19 13:46:57 -05:00
Noah Khamliche
82d42eeede address to lowercase 2021-11-19 13:46:57 -05:00
Noah Khamliche
6ef4d95043 Updated Sushiswap router on CELO
Sushi address in the docs was incorrect, this is the correct address `0x1421bDe4B10e8dd459b3BCb598810B1337D56842`.
2021-11-19 13:46:57 -05:00
Github Actions
6044140f86 Publish
- @0x/asset-swapper@16.36.0
2021-11-19 02:59:33 +00:00
Github Actions
4da1ef0f56 Updated CHANGELOGS & MD docs 2021-11-19 02:59:30 +00:00
Jacob Evans
8c668a3918 feat: Specify FEI/TRIBE liquid pool (#371)
* feat: Specify FEI/TRIBE liquid pool

* CHANGELOG

* FXS/FRAX and OHM/FRAX
2021-11-18 15:39:07 +10:00
Github Actions
f1ff1cde39 Publish
- @0x/asset-swapper@16.35.0
2021-11-18 03:31:36 +00:00
Github Actions
1668a24e31 Updated CHANGELOGS & MD docs 2021-11-18 03:31:32 +00:00
Shawn
4b7c376d96 feat: Add Beethoven X, MorpheusSwap and JetSwap on Fantom (#370)
* Rebase to development branch

* add support for MorpheusSwap and JetSwap on Fantom

* fix lint

* modify changelog.json for asset-swapper

* fix the comments

* prettier

* Use BalancerV2PoolsCache for BeethovenX

Co-authored-by: Romain Butteaud <romain.butteaud@gmail.com>
2021-11-17 19:14:01 -08:00
Github Actions
bb4a9c656c Publish
- @0x/contracts-erc20@3.3.23
 - @0x/contracts-test-utils@5.4.14
 - @0x/contracts-treasury@1.4.6
 - @0x/contracts-utils@4.8.4
 - @0x/contracts-zero-ex@0.29.5
 - @0x/asset-swapper@16.34.0
 - @0x/contract-addresses@6.9.0
 - @0x/contract-wrappers@13.18.3
 - @0x/migrations@8.1.12
 - @0x/protocol-utils@1.9.5
2021-11-16 22:49:46 +00:00
Github Actions
6ab07b6304 Updated CHANGELOGS & MD docs 2021-11-16 22:49:43 +00:00
Noah Khamliche
8903f1ab01 Update packages/contract-addresses/CHANGELOG.json
Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
2021-11-16 16:55:57 -05:00
Noah Khamliche
415535612a removed duplicate celo code 2021-11-16 16:55:57 -05:00
Noah Khamliche
5248a135c3 upped versions in changelog 2021-11-16 16:55:57 -05:00
Lawrence Forman
602290925c fix celo rebase 2021-11-16 16:55:57 -05:00
Github Actions
01813746e8 Publish
- @0x/contracts-zero-ex@0.29.4
 - @0x/asset-swapper@16.33.0
 - @0x/migrations@8.1.11
2021-11-16 12:27:06 +00:00
Github Actions
7d668d8801 Updated CHANGELOGS & MD docs 2021-11-16 12:27:02 +00:00
Jacob Evans
797a00a33a feat: Uniswap V3 1bps pools [TKR-263] (#366)
* feat: Uniswap V3 1bps pools

* Update CHANGELOG
2021-11-16 08:15:24 +10:00
Lawrence Forman
4b3d98f43c @0x/contracts-zero-ex: Prevent EP ETH balance from reducing when executin mtxs (#365)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-11-09 22:11:36 -05:00
Github Actions
9ff77c1cd5 Publish
- @0x/asset-swapper@16.32.0
2021-11-09 19:36:14 +00:00
Github Actions
18a8351671 Updated CHANGELOGS & MD docs 2021-11-09 19:36:10 +00:00
Jorge Pérez
9a994dfcd3 fix: Extended Quote Report Changelog typo 2021-11-09 13:17:14 -06:00
Jorge Pérez
b7adc5a889 feat: Extended Quote Report
* Extended Quote report for indicative quote

* feat: Only save 'full' quotes on quote report

* Unify extended quote report
2021-11-09 13:05:01 -06:00
Github Actions
10b0d7f363 Publish
- @0x/asset-swapper@16.31.0
2021-11-04 06:52:28 +00:00
Github Actions
e2c905a15f Updated CHANGELOGS & MD docs 2021-11-04 06:52:25 +00:00
Jacob Evans
8589ba728c feat: [Avalanche] Add Curve, CurveV2 and KyberDMM (#363)
* feat: [Avalanche] Add Curve, CurveV2 and KyberDMM

* CHANGELOG

* fix missing file

* lint
2021-11-04 16:34:48 +10:00
215 changed files with 26529 additions and 3099 deletions

View File

@@ -4,12 +4,13 @@ jobs:
build:
resource_class: xlarge
docker:
- image: node:12
- image: node:16
environment:
NODE_OPTIONS: '--max-old-space-size=16384'
working_directory: ~/repo
steps:
- checkout
- run: git submodule update --init --recursive
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
- run:
name: install-yarn
@@ -19,7 +20,6 @@ jobs:
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
- setup_remote_docker
- run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
- run: yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts
- save_cache:
key: repo-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -31,7 +31,7 @@ jobs:
test-exchange-ganache:
resource_class: medium+
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
steps:
- restore_cache:
@@ -41,7 +41,7 @@ jobs:
test-integrations-ganache:
resource_class: medium+
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
steps:
- restore_cache:
@@ -51,7 +51,7 @@ jobs:
test-contracts-staking-ganache:
resource_class: medium+
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
steps:
- restore_cache:
@@ -61,7 +61,7 @@ jobs:
test-contracts-extra-ganache:
resource_class: medium+
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
steps:
- restore_cache:
@@ -71,7 +71,7 @@ jobs:
test-contracts-rest-ganache:
resource_class: medium+
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
steps:
- restore_cache:
@@ -83,7 +83,7 @@ jobs:
environment:
NODE_OPTIONS: '--max-old-space-size=6442'
docker:
- image: node:12
- image: node:16
- image: 0xorg/verdaccio
working_directory: ~/repo
steps:
@@ -97,7 +97,7 @@ jobs:
path: ~/.npm/_logs
test-doc-generation:
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
steps:
- restore_cache:
@@ -108,8 +108,10 @@ jobs:
no_output_timeout: 1200
test-rest:
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
environment:
RUST_ROUTER: "true"
steps:
- restore_cache:
keys:
@@ -136,7 +138,7 @@ jobs:
resource_class: large
working_directory: ~/repo
docker:
- image: node:12
- image: node:16
steps:
- restore_cache:
keys:
@@ -147,7 +149,7 @@ jobs:
- run: yarn diff_md_docs:ci
submit-coverage:
docker:
- image: node:12
- image: node:16
working_directory: ~/repo
steps:
- restore_cache:

View File

@@ -28,7 +28,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-node@v1
with:
node-version: 10
node-version: 16
- uses: actions/setup-python@v2
- name: 'configure git'
run: |

9
.gitignore vendored
View File

@@ -173,6 +173,15 @@ contracts/zero-ex/test/generated-wrappers/
contracts/treasury/generated-wrappers/
contracts/treasury/test/generated-wrappers/
# foundry artifacts
contracts/zero-ex/foundry-artifacts/
# foundry cache
contracts/zero-ex/foundry-cache/
# typechain wrappers
contracts/zero-ex/typechain-wrappers/
# Doc README copy
packages/*/docs/README.md

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "contracts/zero-ex/contracts/deps/forge-std"]
path = contracts/zero-ex/contracts/deps/forge-std
url = https://github.com/foundry-rs/forge-std

View File

@@ -1,4 +1,67 @@
[
{
"timestamp": 1650611093,
"version": "3.3.29",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1648739346,
"version": "3.3.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1646225739,
"version": "3.3.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1645569128,
"version": "3.3.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1640364306,
"version": "3.3.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1638390144,
"version": "3.3.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1637102971,
"version": "3.3.23",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1635903615,
"version": "3.3.22",

View File

@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.3.29 - _April 22, 2022_
* Dependencies updated
## v3.3.28 - _March 31, 2022_
* Dependencies updated
## v3.3.27 - _March 2, 2022_
* Dependencies updated
## v3.3.26 - _February 22, 2022_
* Dependencies updated
## v3.3.25 - _December 24, 2021_
* Dependencies updated
## v3.3.24 - _December 1, 2021_
* Dependencies updated
## v3.3.23 - _November 16, 2021_
* Dependencies updated
## v3.3.22 - _November 3, 2021_
* Dependencies updated

View File

@@ -0,0 +1,758 @@
// Copyright (C) 2015, 2016, 2017 Dapphub
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// solhint-disable
pragma solidity ^0.6.5;
contract WETH9 {
string public name = "Wrapped Ether";
string public symbol = "WETH";
uint8 public decimals = 18;
event Approval(address indexed _owner, address indexed _spender, uint _value);
event Transfer(address indexed _from, address indexed _to, uint _value);
event Deposit(address indexed _owner, uint _value);
event Withdrawal(address indexed _owner, uint _value);
mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance;
receive() external payable {
deposit();
}
function deposit() public payable {
balanceOf[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint wad) public {
require(balanceOf[msg.sender] >= wad);
balanceOf[msg.sender] -= wad;
msg.sender.transfer(wad);
emit Withdrawal(msg.sender, wad);
}
function totalSupply() public view returns (uint) {
return address(this).balance;
}
function approve(address guy, uint wad) public returns (bool) {
allowance[msg.sender][guy] = wad;
emit Approval(msg.sender, guy, wad);
return true;
}
function transfer(address dst, uint wad) public returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
returns (bool)
{
require(balanceOf[src] >= wad);
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
require(allowance[src][msg.sender] >= wad);
allowance[src][msg.sender] -= wad;
}
balanceOf[src] -= wad;
balanceOf[dst] += wad;
emit Transfer(src, dst, wad);
return true;
}
}
/*
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
*/

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "3.3.22",
"version": "3.3.29",
"engines": {
"node": ">=6.12"
},
@@ -51,18 +51,18 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/abi-gen": "^5.6.2",
"@0x/contracts-gen": "^2.0.40",
"@0x/contracts-test-utils": "^5.4.13",
"@0x/contracts-utils": "^4.8.3",
"@0x/dev-utils": "^4.2.9",
"@0x/sol-compiler": "^4.7.5",
"@0x/abi-gen": "^5.8.0",
"@0x/contracts-gen": "^2.0.46",
"@0x/contracts-test-utils": "^5.4.20",
"@0x/contracts-utils": "^4.8.10",
"@0x/dev-utils": "^4.2.14",
"@0x/sol-compiler": "^4.8.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.4",
"@0x/types": "^3.3.4",
"@0x/typescript-typings": "^5.2.1",
"@0x/utils": "^6.4.4",
"@0x/web3-wrapper": "^7.6.0",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^6.5.3",
"@0x/web3-wrapper": "^7.6.5",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "12.12.54",
@@ -70,7 +70,7 @@
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"ethereum-types": "^3.6.0",
"ethereum-types": "^3.7.0",
"lodash": "^4.17.11",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
@@ -79,10 +79,10 @@
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "4.2.2"
"typescript": "4.6.3"
},
"dependencies": {
"@0x/base-contract": "^6.4.2",
"@0x/base-contract": "^6.5.0",
"ethers": "~4.0.4"
},
"publishConfig": {

View File

@@ -1,4 +1,67 @@
[
{
"timestamp": 1650611093,
"version": "5.4.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1648739346,
"version": "5.4.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1646225739,
"version": "5.4.18",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1645569128,
"version": "5.4.17",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1640364306,
"version": "5.4.16",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1638390144,
"version": "5.4.15",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1637102971,
"version": "5.4.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1635903615,
"version": "5.4.13",

View File

@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.4.20 - _April 22, 2022_
* Dependencies updated
## v5.4.19 - _March 31, 2022_
* Dependencies updated
## v5.4.18 - _March 2, 2022_
* Dependencies updated
## v5.4.17 - _February 22, 2022_
* Dependencies updated
## v5.4.16 - _December 24, 2021_
* Dependencies updated
## v5.4.15 - _December 1, 2021_
* Dependencies updated
## v5.4.14 - _November 16, 2021_
* Dependencies updated
## v5.4.13 - _November 3, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-test-utils",
"version": "5.4.13",
"version": "5.4.20",
"engines": {
"node": ">=6.12"
},
@@ -34,28 +34,28 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/test-utils",
"devDependencies": {
"@0x/sol-compiler": "^4.7.5",
"@0x/sol-compiler": "^4.8.1",
"@0x/tslint-config": "^4.1.4",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "4.2.2"
"typescript": "4.6.3"
},
"dependencies": {
"@0x/assert": "^3.0.29",
"@0x/base-contract": "^6.4.2",
"@0x/contract-addresses": "^6.8.1",
"@0x/dev-utils": "^4.2.9",
"@0x/json-schemas": "^6.3.0",
"@0x/assert": "^3.0.34",
"@0x/base-contract": "^6.5.0",
"@0x/contract-addresses": "^6.13.0",
"@0x/dev-utils": "^4.2.14",
"@0x/json-schemas": "^6.4.4",
"@0x/order-utils": "^10.4.28",
"@0x/sol-coverage": "^4.0.39",
"@0x/sol-profiler": "^4.1.29",
"@0x/sol-trace": "^3.0.39",
"@0x/subproviders": "^6.6.0",
"@0x/types": "^3.3.4",
"@0x/typescript-typings": "^5.2.1",
"@0x/utils": "^6.4.4",
"@0x/web3-wrapper": "^7.6.0",
"@0x/sol-coverage": "^4.0.45",
"@0x/sol-profiler": "^4.1.35",
"@0x/sol-trace": "^3.0.45",
"@0x/subproviders": "^6.6.5",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^6.5.3",
"@0x/web3-wrapper": "^7.6.5",
"@types/bn.js": "^4.11.0",
"@types/js-combinatorics": "^0.5.29",
"@types/lodash": "4.14.104",
@@ -67,7 +67,7 @@
"chai-bignumber": "^3.0.0",
"decimal.js": "^10.2.0",
"dirty-chai": "^2.0.1",
"ethereum-types": "^3.6.0",
"ethereum-types": "^3.7.0",
"ethereumjs-util": "^7.0.10",
"ethers": "~4.0.4",
"js-combinatorics": "^0.5.3",

View File

@@ -1,4 +1,67 @@
[
{
"timestamp": 1650611093,
"version": "1.4.12",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1648739346,
"version": "1.4.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1646225739,
"version": "1.4.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1645569128,
"version": "1.4.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1640364306,
"version": "1.4.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1638390144,
"version": "1.4.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1637102971,
"version": "1.4.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1635903615,
"version": "1.4.5",

View File

@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.4.12 - _April 22, 2022_
* Dependencies updated
## v1.4.11 - _March 31, 2022_
* Dependencies updated
## v1.4.10 - _March 2, 2022_
* Dependencies updated
## v1.4.9 - _February 22, 2022_
* Dependencies updated
## v1.4.8 - _December 24, 2021_
* Dependencies updated
## v1.4.7 - _December 1, 2021_
* Dependencies updated
## v1.4.6 - _November 16, 2021_
* Dependencies updated
## v1.4.5 - _November 3, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-treasury",
"version": "1.4.5",
"version": "1.4.12",
"engines": {
"node": ">=6.12"
},
@@ -46,14 +46,14 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
"devDependencies": {
"@0x/abi-gen": "^5.6.2",
"@0x/contract-addresses": "^6.8.1",
"@0x/abi-gen": "^5.8.0",
"@0x/contract-addresses": "^6.13.0",
"@0x/contracts-asset-proxy": "^3.7.19",
"@0x/contracts-erc20": "^3.3.22",
"@0x/contracts-gen": "^2.0.40",
"@0x/contracts-erc20": "^3.3.29",
"@0x/contracts-gen": "^2.0.46",
"@0x/contracts-staking": "^2.0.45",
"@0x/contracts-test-utils": "^5.4.13",
"@0x/sol-compiler": "^4.7.5",
"@0x/contracts-test-utils": "^5.4.20",
"@0x/sol-compiler": "^4.8.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.4",
"@types/isomorphic-fetch": "^0.0.35",
@@ -69,17 +69,17 @@
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "4.2.2"
"typescript": "4.6.3"
},
"dependencies": {
"@0x/base-contract": "^6.4.2",
"@0x/protocol-utils": "^1.9.4",
"@0x/subproviders": "^6.6.0",
"@0x/types": "^3.3.4",
"@0x/typescript-typings": "^5.2.1",
"@0x/utils": "^6.4.4",
"@0x/web3-wrapper": "^7.6.0",
"ethereum-types": "^3.6.0",
"@0x/base-contract": "^6.5.0",
"@0x/protocol-utils": "^11.12.0",
"@0x/subproviders": "^6.6.5",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^6.5.3",
"@0x/web3-wrapper": "^7.6.5",
"ethereum-types": "^3.7.0",
"ethereumjs-util": "^7.0.10"
},
"publishConfig": {

View File

@@ -1,4 +1,67 @@
[
{
"timestamp": 1650611093,
"version": "4.8.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1648739346,
"version": "4.8.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1646225739,
"version": "4.8.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1645569128,
"version": "4.8.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1640364306,
"version": "4.8.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1638390144,
"version": "4.8.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1637102971,
"version": "4.8.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1635903615,
"version": "4.8.3",

View File

@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.8.10 - _April 22, 2022_
* Dependencies updated
## v4.8.9 - _March 31, 2022_
* Dependencies updated
## v4.8.8 - _March 2, 2022_
* Dependencies updated
## v4.8.7 - _February 22, 2022_
* Dependencies updated
## v4.8.6 - _December 24, 2021_
* Dependencies updated
## v4.8.5 - _December 1, 2021_
* Dependencies updated
## v4.8.4 - _November 16, 2021_
* Dependencies updated
## v4.8.3 - _November 3, 2021_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-utils",
"version": "4.8.3",
"version": "4.8.10",
"engines": {
"node": ">=6.12"
},
@@ -50,15 +50,15 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/utils",
"devDependencies": {
"@0x/abi-gen": "^5.6.2",
"@0x/contracts-gen": "^2.0.40",
"@0x/contracts-test-utils": "^5.4.13",
"@0x/dev-utils": "^4.2.9",
"@0x/abi-gen": "^5.8.0",
"@0x/contracts-gen": "^2.0.46",
"@0x/contracts-test-utils": "^5.4.20",
"@0x/dev-utils": "^4.2.14",
"@0x/order-utils": "^10.4.28",
"@0x/sol-compiler": "^4.7.5",
"@0x/sol-compiler": "^4.8.1",
"@0x/tslint-config": "^4.1.4",
"@0x/types": "^3.3.4",
"@0x/web3-wrapper": "^7.6.0",
"@0x/types": "^3.3.6",
"@0x/web3-wrapper": "^7.6.5",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
@@ -76,14 +76,14 @@
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typescript": "4.2.2"
"typescript": "4.6.3"
},
"dependencies": {
"@0x/base-contract": "^6.4.2",
"@0x/typescript-typings": "^5.2.1",
"@0x/utils": "^6.4.4",
"@0x/base-contract": "^6.5.0",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^6.5.3",
"bn.js": "^4.11.8",
"ethereum-types": "^3.6.0"
"ethereum-types": "^3.7.0"
},
"publishConfig": {
"access": "public"

View File

@@ -1,4 +1,80 @@
[
{
"version": "0.32.0",
"changes": [
{
"note": "Add support for `BalancerV2Batch` fills in FQT",
"pr": 462
}
],
"timestamp": 1650611093
},
{
"timestamp": 1648739346,
"version": "0.31.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1646225739,
"version": "0.31.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "0.31.0",
"changes": [
{
"note": "Add ERC721OrdersFeature, ERC1155OrdersFeature, and ERC165Feature",
"pr": 429
}
],
"timestamp": 1645569128
},
{
"timestamp": 1640364306,
"version": "0.30.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "0.30.0",
"changes": [
{
"note": "Add `AaveV2` and `Compound` deposit/withdrawal liquidity source",
"pr": 321
}
],
"timestamp": 1638390144
},
{
"timestamp": 1637102971,
"version": "0.29.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "0.29.4",
"changes": [
{
"note": "Prevent EP ETH balance from reducing when executin mtxs",
"pr": 365
}
],
"timestamp": 1637065617
},
{
"version": "0.29.3",
"changes": [

View File

@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v0.32.0 - _April 22, 2022_
* Add support for `BalancerV2Batch` fills in FQT (#462)
## v0.31.2 - _March 31, 2022_
* Dependencies updated
## v0.31.1 - _March 2, 2022_
* Dependencies updated
## v0.31.0 - _February 22, 2022_
* Add ERC721OrdersFeature, ERC1155OrdersFeature, and ERC165Feature (#429)
## v0.30.1 - _December 24, 2021_
* Dependencies updated
## v0.30.0 - _December 1, 2021_
* Add `AaveV2` and `Compound` deposit/withdrawal liquidity source (#321)
## v0.29.5 - _November 16, 2021_
* Dependencies updated
## v0.29.4 - _November 16, 2021_
* Prevent EP ETH balance from reducing when executin mtxs (#365)
## v0.29.3 - _November 3, 2021_
* Register transformERC20() and remove transformERC20Staging() (#355)

View File

@@ -34,6 +34,9 @@ import "./features/interfaces/IBatchFillNativeOrdersFeature.sol";
import "./features/interfaces/IMultiplexFeature.sol";
import "./features/interfaces/IOtcOrdersFeature.sol";
import "./features/interfaces/IFundRecoveryFeature.sol";
import "./features/interfaces/IERC721OrdersFeature.sol";
import "./features/interfaces/IERC1155OrdersFeature.sol";
import "./features/interfaces/IERC165Feature.sol";
/// @dev Interface for a fully featured Exchange Proxy.
@@ -50,7 +53,10 @@ interface IZeroEx is
IBatchFillNativeOrdersFeature,
IMultiplexFeature,
IOtcOrdersFeature,
IFundRecoveryFeature
IFundRecoveryFeature,
IERC721OrdersFeature,
IERC1155OrdersFeature,
IERC165Feature
{
// solhint-disable state-visibility

View File

@@ -0,0 +1,229 @@
// 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;
library LibNFTOrdersRichErrors {
// solhint-disable func-name-mixedcase
function OverspentEthError(
uint256 ethSpent,
uint256 ethAvailable
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("OverspentEthError(uint256,uint256)")),
ethSpent,
ethAvailable
);
}
function InsufficientEthError(
uint256 ethAvailable,
uint256 orderAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InsufficientEthError(uint256,uint256)")),
ethAvailable,
orderAmount
);
}
function ERC721TokenMismatchError(
address token1,
address token2
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("ERC721TokenMismatchError(address,address)")),
token1,
token2
);
}
function ERC1155TokenMismatchError(
address token1,
address token2
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("ERC1155TokenMismatchError(address,address)")),
token1,
token2
);
}
function ERC20TokenMismatchError(
address token1,
address token2
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("ERC20TokenMismatchError(address,address)")),
token1,
token2
);
}
function NegativeSpreadError(
uint256 sellOrderAmount,
uint256 buyOrderAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("NegativeSpreadError(uint256,uint256)")),
sellOrderAmount,
buyOrderAmount
);
}
function SellOrderFeesExceedSpreadError(
uint256 sellOrderFees,
uint256 spread
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("SellOrderFeesExceedSpreadError(uint256,uint256)")),
sellOrderFees,
spread
);
}
function OnlyTakerError(
address sender,
address taker
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("OnlyTakerError(address,address)")),
sender,
taker
);
}
function InvalidSignerError(
address maker,
address signer
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InvalidSignerError(address,address)")),
maker,
signer
);
}
function OrderNotFillableError(
address maker,
uint256 nonce,
uint8 orderStatus
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("OrderNotFillableError(address,uint256,uint8)")),
maker,
nonce,
orderStatus
);
}
function TokenIdMismatchError(
uint256 tokenId,
uint256 orderTokenId
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("TokenIdMismatchError(uint256,uint256)")),
tokenId,
orderTokenId
);
}
function PropertyValidationFailedError(
address propertyValidator,
address token,
uint256 tokenId,
bytes memory propertyData,
bytes memory errorData
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("PropertyValidationFailedError(address,address,uint256,bytes,bytes)")),
propertyValidator,
token,
tokenId,
propertyData,
errorData
);
}
function ExceedsRemainingOrderAmount(
uint128 remainingOrderAmount,
uint128 fillAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("ExceedsRemainingOrderAmount(uint128,uint128)")),
remainingOrderAmount,
fillAmount
);
}
}

View File

@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "../fixins/FixinCommon.sol";
import "./interfaces/IFeature.sol";
/// @dev Implements the ERC165 `supportsInterface` function
contract ERC165Feature is
IFeature,
FixinCommon
{
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "ERC165";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev Indicates whether the 0x Exchange Proxy implements a particular
/// ERC165 interface. This function should use at most 30,000 gas.
/// @param interfaceId The interface identifier, as specified in ERC165.
/// @return isSupported Whether the given interface is supported by the
/// 0x Exchange Proxy.
function supportInterface(bytes4 interfaceId)
external
pure
returns (bool isSupported)
{
return interfaceId == 0x01ffc9a7 || // ERC-165 support
interfaceId == 0x150b7a02 || // ERC-721 `ERC721TokenReceiver` support
interfaceId == 0x4e2312e0; // ERC-1155 `ERC1155TokenReceiver` support
}
}

View File

@@ -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, 2, 0);
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 1);
/// @dev EIP712 typehash of the `MetaTransactionData` struct.
bytes32 public immutable MTX_EIP712_TYPEHASH = keccak256(
"MetaTransactionData("
@@ -105,6 +105,17 @@ contract MetaTransactionsFeature is
}
}
/// @dev Ensures that the ETH balance of `this` does not go below the
/// initial ETH balance before the call (excluding ETH attached to the call).
modifier doesNotReduceEthBalance() {
uint256 initialBalance = address(this).balance - msg.value;
_;
require(
initialBalance <= address(this).balance,
"MetaTransactionsFeature/ETH_LEAK"
);
}
constructor(address zeroExAddress)
public
FixinCommon()
@@ -140,6 +151,7 @@ contract MetaTransactionsFeature is
payable
override
nonReentrant(REENTRANCY_MTX)
doesNotReduceEthBalance
refundsAttachedEth
returns (bytes memory returnResult)
{
@@ -164,6 +176,7 @@ contract MetaTransactionsFeature is
payable
override
nonReentrant(REENTRANCY_MTX)
doesNotReduceEthBalance
refundsAttachedEth
returns (bytes[] memory returnResults)
{

View File

@@ -311,7 +311,7 @@ contract OtcOrdersFeature is
// Unwrap WETH
WETH.withdraw(order.makerAmount);
// Transfer ETH to taker
_transferEth(taker, order.makerAmount);
_transferEth(payable(taker), order.makerAmount);
emit OtcOrderFilled(
orderInfo.orderHash,
@@ -622,16 +622,4 @@ contract OtcOrdersFeature is
[txOrigin]
[nonceBucket];
}
function _transferEth(address recipient, uint256 amount)
private
{
// Transfer ETH to recipient
(bool success, bytes memory revertData) =
recipient.call{value: amount}("");
// Revert on failure
if (!success) {
revertData.rrevert();
}
}
}

View File

@@ -0,0 +1,242 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../libs/LibNFTOrder.sol";
import "../libs/LibSignature.sol";
import "../../vendor/IERC1155Token.sol";
/// @dev Feature for interacting with ERC1155 orders.
interface IERC1155OrdersFeature {
/// @dev Emitted whenever an `ERC1155Order` is filled.
/// @param direction Whether the order is selling or
/// buying the ERC1155 token.
/// @param maker The maker of the order.
/// @param taker The taker of the order.
/// @param nonce The unique maker nonce in the order.
/// @param erc20Token The address of the ERC20 token.
/// @param erc20FillAmount The amount of ERC20 token filled.
/// @param erc1155Token The address of the ERC1155 token.
/// @param erc1155TokenId The ID of the ERC1155 asset.
/// @param erc1155FillAmount The amount of ERC1155 asset filled.
/// @param matcher Currently unused.
event ERC1155OrderFilled(
LibNFTOrder.TradeDirection direction,
address maker,
address taker,
uint256 nonce,
IERC20TokenV06 erc20Token,
uint256 erc20FillAmount,
IERC1155Token erc1155Token,
uint256 erc1155TokenId,
uint128 erc1155FillAmount,
address matcher
);
/// @dev Emitted whenever an `ERC1155Order` is cancelled.
/// @param maker The maker of the order.
/// @param nonce The nonce of the order that was cancelled.
event ERC1155OrderCancelled(
address maker,
uint256 nonce
);
/// @dev Emitted when an `ERC1155Order` is pre-signed.
/// Contains all the fields of the order.
event ERC1155OrderPreSigned(
LibNFTOrder.TradeDirection direction,
address maker,
address taker,
uint256 expiry,
uint256 nonce,
IERC20TokenV06 erc20Token,
uint256 erc20TokenAmount,
LibNFTOrder.Fee[] fees,
IERC1155Token erc1155Token,
uint256 erc1155TokenId,
LibNFTOrder.Property[] erc1155TokenProperties,
uint128 erc1155TokenAmount
);
/// @dev Sells an ERC1155 asset to fill the given order.
/// @param buyOrder The ERC1155 buy order.
/// @param signature The order signature from the maker.
/// @param erc1155TokenId The ID of the ERC1155 asset being
/// sold. If the given order specifies properties,
/// the asset must satisfy those properties. Otherwise,
/// it must equal the tokenId in the order.
/// @param erc1155SellAmount The amount of the ERC1155 asset
/// to sell.
/// @param unwrapNativeToken If this parameter is true and the
/// ERC20 token of the order is e.g. WETH, unwraps the
/// token before transferring it to the taker.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC1155OrderCallback` on `msg.sender` after
/// the ERC20 tokens have been transferred to `msg.sender`
/// but before transferring the ERC1155 asset to the buyer.
function sellERC1155(
LibNFTOrder.ERC1155Order calldata buyOrder,
LibSignature.Signature calldata signature,
uint256 erc1155TokenId,
uint128 erc1155SellAmount,
bool unwrapNativeToken,
bytes calldata callbackData
)
external;
/// @dev Buys an ERC1155 asset by filling the given order.
/// @param sellOrder The ERC1155 sell order.
/// @param signature The order signature.
/// @param erc1155BuyAmount The amount of the ERC1155 asset
/// to buy.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC1155OrderCallback` on `msg.sender` after
/// the ERC1155 asset has been transferred to `msg.sender`
/// but before transferring the ERC20 tokens to the seller.
/// Native tokens acquired during the callback can be used
/// to fill the order.
function buyERC1155(
LibNFTOrder.ERC1155Order calldata sellOrder,
LibSignature.Signature calldata signature,
uint128 erc1155BuyAmount,
bytes calldata callbackData
)
external
payable;
/// @dev Cancel a single ERC1155 order by its nonce. The caller
/// should be the maker of the order. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonce The order nonce.
function cancelERC1155Order(uint256 orderNonce)
external;
/// @dev Cancel multiple ERC1155 orders by their nonces. The caller
/// should be the maker of the orders. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonces The order nonces.
function batchCancelERC1155Orders(uint256[] calldata orderNonces)
external;
/// @dev Buys multiple ERC1155 assets by filling the
/// given orders.
/// @param sellOrders The ERC1155 sell orders.
/// @param signatures The order signatures.
/// @param erc1155TokenAmounts The amounts of the ERC1155 assets
/// to buy for each order.
/// @param callbackData The data (if any) to pass to the taker
/// callback for each order. Refer to the `callbackData`
/// parameter to for `buyERC1155`.
/// @param revertIfIncomplete If true, reverts if this
/// function fails to fill any individual order.
/// @return successes An array of booleans corresponding to whether
/// each order in `orders` was successfully filled.
function batchBuyERC1155s(
LibNFTOrder.ERC1155Order[] calldata sellOrders,
LibSignature.Signature[] calldata signatures,
uint128[] calldata erc1155TokenAmounts,
bytes[] calldata callbackData,
bool revertIfIncomplete
)
external
payable
returns (bool[] memory successes);
/// @dev Callback for the ERC1155 `safeTransferFrom` function.
/// This callback can be used to sell an ERC1155 asset if
/// a valid ERC1155 order, signature and `unwrapNativeToken`
/// are encoded in `data`. This allows takers to sell their
/// ERC1155 asset without first calling `setApprovalForAll`.
/// @param operator The address which called `safeTransferFrom`.
/// @param from The address which previously owned the token.
/// @param tokenId The ID of the asset being transferred.
/// @param value The amount being transferred.
/// @param data Additional data with no specified format. If a
/// valid ERC1155 order, signature and `unwrapNativeToken`
/// are encoded in `data`, this function will try to fill
/// the order using the received asset.
/// @return success The selector of this function (0xf23a6e61),
/// indicating that the callback succeeded.
function onERC1155Received(
address operator,
address from,
uint256 tokenId,
uint256 value,
bytes calldata data
)
external
returns (bytes4 success);
/// @dev Approves an ERC1155 order on-chain. After pre-signing
/// the order, the `PRESIGNED` signature type will become
/// valid for that order and signer.
/// @param order An ERC1155 order.
function preSignERC1155Order(LibNFTOrder.ERC1155Order calldata order)
external;
/// @dev Checks whether the given signature is valid for the
/// the given ERC1155 order. Reverts if not.
/// @param order The ERC1155 order.
/// @param signature The signature to validate.
function validateERC1155OrderSignature(
LibNFTOrder.ERC1155Order calldata order,
LibSignature.Signature calldata signature
)
external
view;
/// @dev If the given order is buying an ERC1155 asset, checks
/// whether or not the given token ID satisfies the required
/// properties specified in the order. If the order does not
/// specify any properties, this function instead checks
/// whether the given token ID matches the ID in the order.
/// Reverts if any checks fail, or if the order is selling
/// an ERC1155 asset.
/// @param order The ERC1155 order.
/// @param erc1155TokenId The ID of the ERC1155 asset.
function validateERC1155OrderProperties(
LibNFTOrder.ERC1155Order calldata order,
uint256 erc1155TokenId
)
external
view;
/// @dev Get the order info for an ERC1155 order.
/// @param order The ERC1155 order.
/// @return orderInfo Infor about the order.
function getERC1155OrderInfo(LibNFTOrder.ERC1155Order calldata order)
external
view
returns (LibNFTOrder.OrderInfo memory orderInfo);
/// @dev Get the EIP-712 hash of an ERC1155 order.
/// @param order The ERC1155 order.
/// @return orderHash The order hash.
function getERC1155OrderHash(LibNFTOrder.ERC1155Order calldata order)
external
view
returns (bytes32 orderHash);
}

View File

@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
/// @dev Implements the ERC165 `supportsInterface` function
interface IERC165Feature {
/// @dev Indicates whether the 0x Exchange Proxy implements a particular
/// ERC165 interface. This function should use at most 30,000 gas.
/// @param interfaceId The interface identifier, as specified in ERC165.
/// @return isSupported Whether the given interface is supported by the
/// 0x Exchange Proxy.
function supportInterface(bytes4 interfaceId)
external
pure
returns (bool isSupported);
}

View File

@@ -0,0 +1,286 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../libs/LibNFTOrder.sol";
import "../libs/LibSignature.sol";
import "../../vendor/IERC721Token.sol";
/// @dev Feature for interacting with ERC721 orders.
interface IERC721OrdersFeature {
/// @dev Emitted whenever an `ERC721Order` is filled.
/// @param direction Whether the order is selling or
/// buying the ERC721 token.
/// @param maker The maker of the order.
/// @param taker The taker of the order.
/// @param nonce The unique maker nonce in the order.
/// @param erc20Token The address of the ERC20 token.
/// @param erc20TokenAmount The amount of ERC20 token
/// to sell or buy.
/// @param erc721Token The address of the ERC721 token.
/// @param erc721TokenId The ID of the ERC721 asset.
/// @param matcher If this order was matched with another using `matchERC721Orders()`,
/// this will be the address of the caller. If not, this will be `address(0)`.
event ERC721OrderFilled(
LibNFTOrder.TradeDirection direction,
address maker,
address taker,
uint256 nonce,
IERC20TokenV06 erc20Token,
uint256 erc20TokenAmount,
IERC721Token erc721Token,
uint256 erc721TokenId,
address matcher
);
/// @dev Emitted whenever an `ERC721Order` is cancelled.
/// @param maker The maker of the order.
/// @param nonce The nonce of the order that was cancelled.
event ERC721OrderCancelled(
address maker,
uint256 nonce
);
/// @dev Emitted when an `ERC721Order` is pre-signed.
/// Contains all the fields of the order.
event ERC721OrderPreSigned(
LibNFTOrder.TradeDirection direction,
address maker,
address taker,
uint256 expiry,
uint256 nonce,
IERC20TokenV06 erc20Token,
uint256 erc20TokenAmount,
LibNFTOrder.Fee[] fees,
IERC721Token erc721Token,
uint256 erc721TokenId,
LibNFTOrder.Property[] erc721TokenProperties
);
/// @dev Sells an ERC721 asset to fill the given order.
/// @param buyOrder The ERC721 buy order.
/// @param signature The order signature from the maker.
/// @param erc721TokenId The ID of the ERC721 asset being
/// sold. If the given order specifies properties,
/// the asset must satisfy those properties. Otherwise,
/// it must equal the tokenId in the order.
/// @param unwrapNativeToken If this parameter is true and the
/// ERC20 token of the order is e.g. WETH, unwraps the
/// token before transferring it to the taker.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC721OrderCallback` on `msg.sender` after
/// the ERC20 tokens have been transferred to `msg.sender`
/// but before transferring the ERC721 asset to the buyer.
function sellERC721(
LibNFTOrder.ERC721Order calldata buyOrder,
LibSignature.Signature calldata signature,
uint256 erc721TokenId,
bool unwrapNativeToken,
bytes calldata callbackData
)
external;
/// @dev Buys an ERC721 asset by filling the given order.
/// @param sellOrder The ERC721 sell order.
/// @param signature The order signature.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC721OrderCallback` on `msg.sender` after
/// the ERC721 asset has been transferred to `msg.sender`
/// but before transferring the ERC20 tokens to the seller.
/// Native tokens acquired during the callback can be used
/// to fill the order.
function buyERC721(
LibNFTOrder.ERC721Order calldata sellOrder,
LibSignature.Signature calldata signature,
bytes calldata callbackData
)
external
payable;
/// @dev Cancel a single ERC721 order by its nonce. The caller
/// should be the maker of the order. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonce The order nonce.
function cancelERC721Order(uint256 orderNonce)
external;
/// @dev Cancel multiple ERC721 orders by their nonces. The caller
/// should be the maker of the orders. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonces The order nonces.
function batchCancelERC721Orders(uint256[] calldata orderNonces)
external;
/// @dev Buys multiple ERC721 assets by filling the
/// given orders.
/// @param sellOrders The ERC721 sell orders.
/// @param signatures The order signatures.
/// @param callbackData The data (if any) to pass to the taker
/// callback for each order. Refer to the `callbackData`
/// parameter to for `buyERC721`.
/// @param revertIfIncomplete If true, reverts if this
/// function fails to fill any individual order.
/// @return successes An array of booleans corresponding to whether
/// each order in `orders` was successfully filled.
function batchBuyERC721s(
LibNFTOrder.ERC721Order[] calldata sellOrders,
LibSignature.Signature[] calldata signatures,
bytes[] calldata callbackData,
bool revertIfIncomplete
)
external
payable
returns (bool[] memory successes);
/// @dev Matches a pair of complementary orders that have
/// a non-negative spread. Each order is filled at
/// their respective price, and the matcher receives
/// a profit denominated in the ERC20 token.
/// @param sellOrder Order selling an ERC721 asset.
/// @param buyOrder Order buying an ERC721 asset.
/// @param sellOrderSignature Signature for the sell order.
/// @param buyOrderSignature Signature for the buy order.
/// @return profit The amount of profit earned by the caller
/// of this function (denominated in the ERC20 token
/// of the matched orders).
function matchERC721Orders(
LibNFTOrder.ERC721Order calldata sellOrder,
LibNFTOrder.ERC721Order calldata buyOrder,
LibSignature.Signature calldata sellOrderSignature,
LibSignature.Signature calldata buyOrderSignature
)
external
returns (uint256 profit);
/// @dev Matches pairs of complementary orders that have
/// non-negative spreads. Each order is filled at
/// their respective price, and the matcher receives
/// a profit denominated in the ERC20 token.
/// @param sellOrders Orders selling ERC721 assets.
/// @param buyOrders Orders buying ERC721 assets.
/// @param sellOrderSignatures Signatures for the sell orders.
/// @param buyOrderSignatures Signatures for the buy orders.
/// @return profits The amount of profit earned by the caller
/// of this function for each pair of matched orders
/// (denominated in the ERC20 token of the order pair).
/// @return successes An array of booleans corresponding to
/// whether each pair of orders was successfully matched.
function batchMatchERC721Orders(
LibNFTOrder.ERC721Order[] calldata sellOrders,
LibNFTOrder.ERC721Order[] calldata buyOrders,
LibSignature.Signature[] calldata sellOrderSignatures,
LibSignature.Signature[] calldata buyOrderSignatures
)
external
returns (uint256[] memory profits, bool[] memory successes);
/// @dev Callback for the ERC721 `safeTransferFrom` function.
/// This callback can be used to sell an ERC721 asset if
/// a valid ERC721 order, signature and `unwrapNativeToken`
/// are encoded in `data`. This allows takers to sell their
/// ERC721 asset without first calling `setApprovalForAll`.
/// @param operator The address which called `safeTransferFrom`.
/// @param from The address which previously owned the token.
/// @param tokenId The ID of the asset being transferred.
/// @param data Additional data with no specified format. If a
/// valid ERC721 order, signature and `unwrapNativeToken`
/// are encoded in `data`, this function will try to fill
/// the order using the received asset.
/// @return success The selector of this function (0x150b7a02),
/// indicating that the callback succeeded.
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
)
external
returns (bytes4 success);
/// @dev Approves an ERC721 order on-chain. After pre-signing
/// the order, the `PRESIGNED` signature type will become
/// valid for that order and signer.
/// @param order An ERC721 order.
function preSignERC721Order(LibNFTOrder.ERC721Order calldata order)
external;
/// @dev Checks whether the given signature is valid for the
/// the given ERC721 order. Reverts if not.
/// @param order The ERC721 order.
/// @param signature The signature to validate.
function validateERC721OrderSignature(
LibNFTOrder.ERC721Order calldata order,
LibSignature.Signature calldata signature
)
external
view;
/// @dev If the given order is buying an ERC721 asset, checks
/// whether or not the given token ID satisfies the required
/// properties specified in the order. If the order does not
/// specify any properties, this function instead checks
/// whether the given token ID matches the ID in the order.
/// Reverts if any checks fail, or if the order is selling
/// an ERC721 asset.
/// @param order The ERC721 order.
/// @param erc721TokenId The ID of the ERC721 asset.
function validateERC721OrderProperties(
LibNFTOrder.ERC721Order calldata order,
uint256 erc721TokenId
)
external
view;
/// @dev Get the current status of an ERC721 order.
/// @param order The ERC721 order.
/// @return status The status of the order.
function getERC721OrderStatus(LibNFTOrder.ERC721Order calldata order)
external
view
returns (LibNFTOrder.OrderStatus status);
/// @dev Get the EIP-712 hash of an ERC721 order.
/// @param order The ERC721 order.
/// @return orderHash The order hash.
function getERC721OrderHash(LibNFTOrder.ERC721Order calldata order)
external
view
returns (bytes32 orderHash);
/// @dev Get the order status bit vector for the given
/// maker address and nonce range.
/// @param maker The maker of the order.
/// @param nonceRange Order status bit vectors are indexed
/// by maker address and the upper 248 bits of the
/// order nonce. We define `nonceRange` to be these
/// 248 bits.
/// @return bitVector The order status bit vector for the
/// given maker and nonce range.
function getERC721OrderStatusBitVector(address maker, uint248 nonceRange)
external
view
returns (uint256 bitVector);
}

View File

@@ -0,0 +1,459 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../../vendor/IERC1155Token.sol";
import "../../vendor/IERC721Token.sol";
import "../../vendor/IPropertyValidator.sol";
/// @dev A library for common NFT order operations.
library LibNFTOrder {
enum OrderStatus {
INVALID,
FILLABLE,
UNFILLABLE,
EXPIRED
}
enum TradeDirection {
SELL_NFT,
BUY_NFT
}
struct Property {
IPropertyValidator propertyValidator;
bytes propertyData;
}
struct Fee {
address recipient;
uint256 amount;
bytes feeData;
}
// "Base struct" for ERC721Order and ERC1155, used
// by the abstract contract `NFTOrders`.
struct NFTOrder {
TradeDirection direction;
address maker;
address taker;
uint256 expiry;
uint256 nonce;
IERC20TokenV06 erc20Token;
uint256 erc20TokenAmount;
Fee[] fees;
address nft;
uint256 nftId;
Property[] nftProperties;
}
// All fields align with those of NFTOrder
struct ERC721Order {
TradeDirection direction;
address maker;
address taker;
uint256 expiry;
uint256 nonce;
IERC20TokenV06 erc20Token;
uint256 erc20TokenAmount;
Fee[] fees;
IERC721Token erc721Token;
uint256 erc721TokenId;
Property[] erc721TokenProperties;
}
// All fields except `erc1155TokenAmount` align
// with those of NFTOrder
struct ERC1155Order {
TradeDirection direction;
address maker;
address taker;
uint256 expiry;
uint256 nonce;
IERC20TokenV06 erc20Token;
uint256 erc20TokenAmount;
Fee[] fees;
IERC1155Token erc1155Token;
uint256 erc1155TokenId;
Property[] erc1155TokenProperties;
// End of fields shared with NFTOrder
uint128 erc1155TokenAmount;
}
struct OrderInfo {
bytes32 orderHash;
OrderStatus status;
// `orderAmount` is 1 for all ERC721Orders, and
// `erc1155TokenAmount` for ERC1155Orders.
uint128 orderAmount;
// The remaining amount of the ERC721/ERC1155 asset
// that can be filled for the order.
uint128 remainingAmount;
}
// The type hash for ERC721 orders, which is:
// keccak256(abi.encodePacked(
// "ERC721Order(",
// "uint8 direction,",
// "address maker,",
// "address taker,",
// "uint256 expiry,",
// "uint256 nonce,",
// "address erc20Token,",
// "uint256 erc20TokenAmount,",
// "Fee[] fees,",
// "address erc721Token,",
// "uint256 erc721TokenId,",
// "Property[] erc721TokenProperties",
// ")",
// "Fee(",
// "address recipient,",
// "uint256 amount,",
// "bytes feeData",
// ")",
// "Property(",
// "address propertyValidator,",
// "bytes propertyData",
// ")"
// ))
uint256 private constant _ERC_721_ORDER_TYPEHASH =
0x2de32b2b090da7d8ab83ca4c85ba2eb6957bc7f6c50cb4ae1995e87560d808ed;
// The type hash for ERC1155 orders, which is:
// keccak256(abi.encodePacked(
// "ERC1155Order(",
// "uint8 direction,",
// "address maker,",
// "address taker,",
// "uint256 expiry,",
// "uint256 nonce,",
// "address erc20Token,",
// "uint256 erc20TokenAmount,",
// "Fee[] fees,",
// "address erc1155Token,",
// "uint256 erc1155TokenId,",
// "Property[] erc1155TokenProperties,",
// "uint128 erc1155TokenAmount",
// ")",
// "Fee(",
// "address recipient,",
// "uint256 amount,",
// "bytes feeData",
// ")",
// "Property(",
// "address propertyValidator,",
// "bytes propertyData",
// ")"
// ))
uint256 private constant _ERC_1155_ORDER_TYPEHASH =
0x930490b1bcedd2e5139e22c761fafd52e533960197c2283f3922c7fd8c880be9;
// keccak256(abi.encodePacked(
// "Fee(",
// "address recipient,",
// "uint256 amount,",
// "bytes feeData",
// ")"
// ))
uint256 private constant _FEE_TYPEHASH =
0xe68c29f1b4e8cce0bbcac76eb1334bdc1dc1f293a517c90e9e532340e1e94115;
// keccak256(abi.encodePacked(
// "Property(",
// "address propertyValidator,",
// "bytes propertyData",
// ")"
// ))
uint256 private constant _PROPERTY_TYPEHASH =
0x6292cf854241cb36887e639065eca63b3af9f7f70270cebeda4c29b6d3bc65e8;
// keccak256("");
bytes32 private constant _EMPTY_ARRAY_KECCAK256 =
0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// keccak256(abi.encodePacked(keccak256(abi.encode(
// _PROPERTY_TYPEHASH,
// address(0),
// keccak256("")
// ))));
bytes32 private constant _NULL_PROPERTY_STRUCT_HASH =
0x720ee400a9024f6a49768142c339bf09d2dd9056ab52d20fbe7165faba6e142d;
uint256 private constant ADDRESS_MASK = (1 << 160) - 1;
// ERC721Order and NFTOrder fields are aligned, so
// we can safely cast an ERC721Order to an NFTOrder.
function asNFTOrder(ERC721Order memory erc721Order)
internal
pure
returns (NFTOrder memory nftOrder)
{
assembly {
nftOrder := erc721Order
}
}
// ERC1155Order and NFTOrder fields are aligned with
// the exception of the last field `erc1155TokenAmount`
// in ERC1155Order, so we can safely cast an ERC1155Order
// to an NFTOrder.
function asNFTOrder(ERC1155Order memory erc1155Order)
internal
pure
returns (NFTOrder memory nftOrder)
{
assembly {
nftOrder := erc1155Order
}
}
// ERC721Order and NFTOrder fields are aligned, so
// we can safely cast an MFTOrder to an ERC721Order.
function asERC721Order(NFTOrder memory nftOrder)
internal
pure
returns (ERC721Order memory erc721Order)
{
assembly {
erc721Order := nftOrder
}
}
// NOTE: This is only safe if `nftOrder` was previously
// cast from an `ERC1155Order` and the original
// `erc1155TokenAmount` memory word has not been corrupted!
function asERC1155Order(
NFTOrder memory nftOrder
)
internal
pure
returns (ERC1155Order memory erc1155Order)
{
assembly {
erc1155Order := nftOrder
}
}
/// @dev Get the struct hash of an ERC721 order.
/// @param order The ERC721 order.
/// @return structHash The struct hash of the order.
function getERC721OrderStructHash(ERC721Order memory order)
internal
pure
returns (bytes32 structHash)
{
bytes32 propertiesHash = _propertiesHash(order.erc721TokenProperties);
bytes32 feesHash = _feesHash(order.fees);
// Hash in place, equivalent to:
// return keccak256(abi.encode(
// _ERC_721_ORDER_TYPEHASH,
// order.direction,
// order.maker,
// order.taker,
// order.expiry,
// order.nonce,
// order.erc20Token,
// order.erc20TokenAmount,
// feesHash,
// order.erc721Token,
// order.erc721TokenId,
// propertiesHash
// ));
assembly {
if lt(order, 32) { invalid() } // Don't underflow memory.
let typeHashPos := sub(order, 32) // order - 32
let feesHashPos := add(order, 224) // order + (32 * 7)
let propertiesHashPos := add(order, 320) // order + (32 * 10)
let typeHashMemBefore := mload(typeHashPos)
let feeHashMemBefore := mload(feesHashPos)
let propertiesHashMemBefore := mload(propertiesHashPos)
mstore(typeHashPos, _ERC_721_ORDER_TYPEHASH)
mstore(feesHashPos, feesHash)
mstore(propertiesHashPos, propertiesHash)
structHash := keccak256(typeHashPos, 384 /* 32 * 12 */ )
mstore(typeHashPos, typeHashMemBefore)
mstore(feesHashPos, feeHashMemBefore)
mstore(propertiesHashPos, propertiesHashMemBefore)
}
return structHash;
}
/// @dev Get the struct hash of an ERC1155 order.
/// @param order The ERC1155 order.
/// @return structHash The struct hash of the order.
function getERC1155OrderStructHash(ERC1155Order memory order)
internal
pure
returns (bytes32 structHash)
{
bytes32 propertiesHash = _propertiesHash(order.erc1155TokenProperties);
bytes32 feesHash = _feesHash(order.fees);
// Hash in place, equivalent to:
// return keccak256(abi.encode(
// _ERC_1155_ORDER_TYPEHASH,
// order.direction,
// order.maker,
// order.taker,
// order.expiry,
// order.nonce,
// order.erc20Token,
// order.erc20TokenAmount,
// feesHash,
// order.erc1155Token,
// order.erc1155TokenId,
// propertiesHash,
// order.erc1155TokenAmount
// ));
assembly {
if lt(order, 32) { invalid() } // Don't underflow memory.
let typeHashPos := sub(order, 32) // order - 32
let feesHashPos := add(order, 224) // order + (32 * 7)
let propertiesHashPos := add(order, 320) // order + (32 * 10)
let typeHashMemBefore := mload(typeHashPos)
let feesHashMemBefore := mload(feesHashPos)
let propertiesHashMemBefore := mload(propertiesHashPos)
mstore(typeHashPos, _ERC_1155_ORDER_TYPEHASH)
mstore(feesHashPos, feesHash)
mstore(propertiesHashPos, propertiesHash)
structHash := keccak256(typeHashPos, 416 /* 32 * 12 */ )
mstore(typeHashPos, typeHashMemBefore)
mstore(feesHashPos, feesHashMemBefore)
mstore(propertiesHashPos, propertiesHashMemBefore)
}
return structHash;
}
// Hashes the `properties` array as part of computing the
// EIP-712 hash of an `ERC721Order` or `ERC1155Order`.
function _propertiesHash(Property[] memory properties)
private
pure
returns (bytes32 propertiesHash)
{
uint256 numProperties = properties.length;
// We give `properties.length == 0` and `properties.length == 1`
// special treatment because we expect these to be the most common.
if (numProperties == 0) {
propertiesHash = _EMPTY_ARRAY_KECCAK256;
} else if (numProperties == 1) {
Property memory property = properties[0];
if (
address(property.propertyValidator) == address(0) &&
property.propertyData.length == 0
) {
propertiesHash = _NULL_PROPERTY_STRUCT_HASH;
} else {
// propertiesHash = keccak256(abi.encodePacked(keccak256(abi.encode(
// _PROPERTY_TYPEHASH,
// properties[0].propertyValidator,
// keccak256(properties[0].propertyData)
// ))));
bytes32 dataHash = keccak256(property.propertyData);
assembly {
// Load free memory pointer
let mem := mload(64)
mstore(mem, _PROPERTY_TYPEHASH)
// property.propertyValidator
mstore(add(mem, 32), and(ADDRESS_MASK, mload(property)))
// keccak256(property.propertyData)
mstore(add(mem, 64), dataHash)
mstore(mem, keccak256(mem, 96))
propertiesHash := keccak256(mem, 32)
}
}
} else {
bytes32[] memory propertyStructHashArray = new bytes32[](numProperties);
for (uint256 i = 0; i < numProperties; i++) {
propertyStructHashArray[i] = keccak256(abi.encode(
_PROPERTY_TYPEHASH,
properties[i].propertyValidator,
keccak256(properties[i].propertyData)
));
}
assembly {
propertiesHash := keccak256(add(propertyStructHashArray, 32), mul(numProperties, 32))
}
}
}
// Hashes the `fees` array as part of computing the
// EIP-712 hash of an `ERC721Order` or `ERC1155Order`.
function _feesHash(Fee[] memory fees)
private
pure
returns (bytes32 feesHash)
{
uint256 numFees = fees.length;
// We give `fees.length == 0` and `fees.length == 1`
// special treatment because we expect these to be the most common.
if (numFees == 0) {
feesHash = _EMPTY_ARRAY_KECCAK256;
} else if (numFees == 1) {
// feesHash = keccak256(abi.encodePacked(keccak256(abi.encode(
// _FEE_TYPEHASH,
// fees[0].recipient,
// fees[0].amount,
// keccak256(fees[0].feeData)
// ))));
Fee memory fee = fees[0];
bytes32 dataHash = keccak256(fee.feeData);
assembly {
// Load free memory pointer
let mem := mload(64)
mstore(mem, _FEE_TYPEHASH)
// fee.recipient
mstore(add(mem, 32), and(ADDRESS_MASK, mload(fee)))
// fee.amount
mstore(add(mem, 64), mload(add(fee, 32)))
// keccak256(fee.feeData)
mstore(add(mem, 96), dataHash)
mstore(mem, keccak256(mem, 128))
feesHash := keccak256(mem, 32)
}
} else {
bytes32[] memory feeStructHashArray = new bytes32[](numFees);
for (uint256 i = 0; i < numFees; i++) {
feeStructHashArray[i] = keccak256(abi.encode(
_FEE_TYPEHASH,
fees[i].recipient,
fees[i].amount,
keccak256(fees[i].feeData)
));
}
assembly {
feesHash := keccak256(add(feeStructHashArray, 32), mul(numFees, 32))
}
}
}
}

View File

@@ -44,7 +44,8 @@ library LibSignature {
ILLEGAL,
INVALID,
EIP712,
ETHSIGN
ETHSIGN,
PRESIGNED
}
/// @dev Encoded EC signature.
@@ -146,6 +147,15 @@ library LibSignature {
).rrevert();
}
// If a feature supports pre-signing, it wouldn't use
// `getSignerOfHash` on a pre-signed order.
if (signature.signatureType == SignatureType.PRESIGNED) {
LibSignatureRichErrors.SignatureValidationError(
LibSignatureRichErrors.SignatureValidationErrorCodes.UNSUPPORTED,
hash
).rrevert();
}
// Solidity should check that the signature type is within enum range for us
// when abi-decoding.
}

View File

@@ -622,15 +622,6 @@ contract MultiplexFeature is
_executeBatchSell(batchSellParams).boughtAmount;
}
// Transfers some amount of ETH to the given recipient and
// reverts if the transfer fails.
function _transferEth(address payable recipient, uint256 amount)
private
{
(bool success,) = recipient.call{value: amount}("");
require(success, "MultiplexFeature::_transferEth/TRANSFER_FAILED");
}
// This function computes the "target" address of hop index `i` within
// a multi-hop sell.
// If `i == 0`, the target is the address which should hold the input

View File

@@ -0,0 +1,635 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../fixins/FixinERC1155Spender.sol";
import "../../migrations/LibMigrate.sol";
import "../../storage/LibERC1155OrdersStorage.sol";
import "../interfaces/IFeature.sol";
import "../interfaces/IERC1155OrdersFeature.sol";
import "../libs/LibNFTOrder.sol";
import "../libs/LibSignature.sol";
import "./NFTOrders.sol";
/// @dev Feature for interacting with ERC1155 orders.
contract ERC1155OrdersFeature is
IFeature,
IERC1155OrdersFeature,
FixinERC1155Spender,
NFTOrders
{
using LibSafeMathV06 for uint256;
using LibSafeMathV06 for uint128;
using LibNFTOrder for LibNFTOrder.ERC1155Order;
using LibNFTOrder for LibNFTOrder.NFTOrder;
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "ERC1155Orders";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev The magic return value indicating the success of a `onERC1155Received`.
bytes4 private constant ERC1155_RECEIVED_MAGIC_BYTES = this.onERC1155Received.selector;
constructor(address zeroExAddress, IEtherTokenV06 weth)
public
NFTOrders(zeroExAddress, weth)
{}
/// @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.sellERC1155.selector);
_registerFeatureFunction(this.buyERC1155.selector);
_registerFeatureFunction(this.cancelERC1155Order.selector);
_registerFeatureFunction(this.batchBuyERC1155s.selector);
_registerFeatureFunction(this.onERC1155Received.selector);
_registerFeatureFunction(this.preSignERC1155Order.selector);
_registerFeatureFunction(this.validateERC1155OrderSignature.selector);
_registerFeatureFunction(this.validateERC1155OrderProperties.selector);
_registerFeatureFunction(this.getERC1155OrderInfo.selector);
_registerFeatureFunction(this.getERC1155OrderHash.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Sells an ERC1155 asset to fill the given order.
/// @param buyOrder The ERC1155 buy order.
/// @param signature The order signature from the maker.
/// @param erc1155TokenId The ID of the ERC1155 asset being
/// sold. If the given order specifies properties,
/// the asset must satisfy those properties. Otherwise,
/// it must equal the tokenId in the order.
/// @param erc1155SellAmount The amount of the ERC1155 asset
/// to sell.
/// @param unwrapNativeToken If this parameter is true and the
/// ERC20 token of the order is e.g. WETH, unwraps the
/// token before transferring it to the taker.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC1155OrderCallback` on `msg.sender` after
/// the ERC20 tokens have been transferred to `msg.sender`
/// but before transferring the ERC1155 asset to the buyer.
function sellERC1155(
LibNFTOrder.ERC1155Order memory buyOrder,
LibSignature.Signature memory signature,
uint256 erc1155TokenId,
uint128 erc1155SellAmount,
bool unwrapNativeToken,
bytes memory callbackData
)
public
override
{
_sellERC1155(
buyOrder,
signature,
SellParams(
erc1155SellAmount,
erc1155TokenId,
unwrapNativeToken,
msg.sender, // taker
msg.sender, // owner
callbackData
)
);
}
/// @dev Buys an ERC1155 asset by filling the given order.
/// @param sellOrder The ERC1155 sell order.
/// @param signature The order signature.
/// @param erc1155BuyAmount The amount of the ERC1155 asset
/// to buy.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC1155OrderCallback` on `msg.sender` after
/// the ERC1155 asset has been transferred to `msg.sender`
/// but before transferring the ERC20 tokens to the seller.
/// Native tokens acquired during the callback can be used
/// to fill the order.
function buyERC1155(
LibNFTOrder.ERC1155Order memory sellOrder,
LibSignature.Signature memory signature,
uint128 erc1155BuyAmount,
bytes memory callbackData
)
public
override
payable
{
uint256 ethBalanceBefore = address(this).balance
.safeSub(msg.value);
_buyERC1155(
sellOrder,
signature,
BuyParams(
erc1155BuyAmount,
msg.value,
callbackData
)
);
uint256 ethBalanceAfter = address(this).balance;
// Cannot use pre-existing ETH balance
if (ethBalanceAfter < ethBalanceBefore) {
LibNFTOrdersRichErrors.OverspentEthError(
ethBalanceBefore - ethBalanceAfter + msg.value,
msg.value
).rrevert();
}
// Refund
_transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
}
/// @dev Cancel a single ERC1155 order by its nonce. The caller
/// should be the maker of the order. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonce The order nonce.
function cancelERC1155Order(uint256 orderNonce)
public
override
{
// The bitvector is indexed by the lower 8 bits of the nonce.
uint256 flag = 1 << (orderNonce & 255);
// Update order cancellation bit vector to indicate that the order
// has been cancelled/filled by setting the designated bit to 1.
LibERC1155OrdersStorage.getStorage().orderCancellationByMaker
[msg.sender][uint248(orderNonce >> 8)] |= flag;
emit ERC1155OrderCancelled(msg.sender, orderNonce);
}
/// @dev Cancel multiple ERC1155 orders by their nonces. The caller
/// should be the maker of the orders. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonces The order nonces.
function batchCancelERC1155Orders(uint256[] calldata orderNonces)
external
override
{
for (uint256 i = 0; i < orderNonces.length; i++) {
cancelERC1155Order(orderNonces[i]);
}
}
/// @dev Buys multiple ERC1155 assets by filling the
/// given orders.
/// @param sellOrders The ERC1155 sell orders.
/// @param signatures The order signatures.
/// @param erc1155FillAmounts The amounts of the ERC1155 assets
/// to buy for each order.
/// @param callbackData The data (if any) to pass to the taker
/// callback for each order. Refer to the `callbackData`
/// parameter to for `buyERC1155`.
/// @param revertIfIncomplete If true, reverts if this
/// function fails to fill any individual order.
/// @return successes An array of booleans corresponding to whether
/// each order in `orders` was successfully filled.
function batchBuyERC1155s(
LibNFTOrder.ERC1155Order[] memory sellOrders,
LibSignature.Signature[] memory signatures,
uint128[] calldata erc1155FillAmounts,
bytes[] memory callbackData,
bool revertIfIncomplete
)
public
override
payable
returns (bool[] memory successes)
{
require(
sellOrders.length == signatures.length &&
sellOrders.length == erc1155FillAmounts.length &&
sellOrders.length == callbackData.length,
"ERC1155OrdersFeature::batchBuyERC1155s/ARRAY_LENGTH_MISMATCH"
);
successes = new bool[](sellOrders.length);
uint256 ethBalanceBefore = address(this).balance
.safeSub(msg.value);
if (revertIfIncomplete) {
for (uint256 i = 0; i < sellOrders.length; i++) {
// Will revert if _buyERC1155 reverts.
_buyERC1155(
sellOrders[i],
signatures[i],
BuyParams(
erc1155FillAmounts[i],
address(this).balance.safeSub(ethBalanceBefore), // Remaining ETH available
callbackData[i]
)
);
successes[i] = true;
}
} else {
for (uint256 i = 0; i < sellOrders.length; i++) {
// Delegatecall `_buyERC1155` to catch swallow reverts while
// preserving execution context.
// Note that `_buyERC1155` is a public function but should _not_
// be registered in the Exchange Proxy.
(successes[i], ) = _implementation.delegatecall(
abi.encodeWithSelector(
this._buyERC1155.selector,
sellOrders[i],
signatures[i],
BuyParams(
erc1155FillAmounts[i],
address(this).balance.safeSub(ethBalanceBefore), // Remaining ETH available
callbackData[i]
)
)
);
}
}
// Cannot use pre-existing ETH balance
uint256 ethBalanceAfter = address(this).balance;
if (ethBalanceAfter < ethBalanceBefore) {
LibNFTOrdersRichErrors.OverspentEthError(
msg.value + (ethBalanceBefore - ethBalanceAfter),
msg.value
).rrevert();
}
// Refund
_transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
}
/// @dev Callback for the ERC1155 `safeTransferFrom` function.
/// This callback can be used to sell an ERC1155 asset if
/// a valid ERC1155 order, signature and `unwrapNativeToken`
/// are encoded in `data`. This allows takers to sell their
/// ERC1155 asset without first calling `setApprovalForAll`.
/// @param operator The address which called `safeTransferFrom`.
/// @param tokenId The ID of the asset being transferred.
/// @param value The amount being transferred.
/// @param data Additional data with no specified format. If a
/// valid ERC1155 order, signature and `unwrapNativeToken`
/// are encoded in `data`, this function will try to fill
/// the order using the received asset.
/// @return success The selector of this function (0xf23a6e61),
/// indicating that the callback succeeded.
function onERC1155Received(
address operator,
address /* from */,
uint256 tokenId,
uint256 value,
bytes calldata data
)
external
override
returns (bytes4 success)
{
// Decode the order, signature, and `unwrapNativeToken` from
// `data`. If `data` does not encode such parameters, this
// will throw.
(
LibNFTOrder.ERC1155Order memory buyOrder,
LibSignature.Signature memory signature,
bool unwrapNativeToken
) = abi.decode(
data,
(LibNFTOrder.ERC1155Order, LibSignature.Signature, bool)
);
// `onERC1155Received` is called by the ERC1155 token contract.
// Check that it matches the ERC1155 token in the order.
if (msg.sender != address(buyOrder.erc1155Token)) {
LibNFTOrdersRichErrors.ERC1155TokenMismatchError(
msg.sender,
address(buyOrder.erc1155Token)
).rrevert();
}
_sellERC1155(
buyOrder,
signature,
SellParams(
value.safeDowncastToUint128(),
tokenId,
unwrapNativeToken,
operator, // taker
address(this), // owner (we hold the NFT currently)
new bytes(0) // No taker callback
)
);
return ERC1155_RECEIVED_MAGIC_BYTES;
}
/// @dev Approves an ERC1155 order on-chain. After pre-signing
/// the order, the `PRESIGNED` signature type will become
/// valid for that order and signer.
/// @param order An ERC1155 order.
function preSignERC1155Order(LibNFTOrder.ERC1155Order memory order)
public
override
{
require(
order.maker == msg.sender,
"ERC1155OrdersFeature::preSignERC1155Order/MAKER_MISMATCH"
);
bytes32 orderHash = getERC1155OrderHash(order);
LibERC1155OrdersStorage.Storage storage stor =
LibERC1155OrdersStorage.getStorage();
// Set `preSigned` to true on the order state variable
// to indicate that the order has been pre-signed.
stor.orderState[orderHash].preSigned = true;
emit ERC1155OrderPreSigned(
order.direction,
order.maker,
order.taker,
order.expiry,
order.nonce,
order.erc20Token,
order.erc20TokenAmount,
order.fees,
order.erc1155Token,
order.erc1155TokenId,
order.erc1155TokenProperties,
order.erc1155TokenAmount
);
}
// Core settlement logic for selling an ERC1155 asset.
// Used by `sellERC1155` and `onERC1155Received`.
function _sellERC1155(
LibNFTOrder.ERC1155Order memory buyOrder,
LibSignature.Signature memory signature,
SellParams memory params
)
private
{
uint256 erc20FillAmount = _sellNFT(
buyOrder.asNFTOrder(),
signature,
params
);
emit ERC1155OrderFilled(
buyOrder.direction,
buyOrder.maker,
params.taker,
buyOrder.nonce,
buyOrder.erc20Token,
erc20FillAmount,
buyOrder.erc1155Token,
params.tokenId,
params.sellAmount,
address(0)
);
}
// Core settlement logic for buying an ERC1155 asset.
// Used by `buyERC1155` and `batchBuyERC1155s`.
function _buyERC1155(
LibNFTOrder.ERC1155Order memory sellOrder,
LibSignature.Signature memory signature,
BuyParams memory params
)
public
payable
{
uint256 erc20FillAmount = _buyNFT(
sellOrder.asNFTOrder(),
signature,
params
);
emit ERC1155OrderFilled(
sellOrder.direction,
sellOrder.maker,
msg.sender,
sellOrder.nonce,
sellOrder.erc20Token,
erc20FillAmount,
sellOrder.erc1155Token,
sellOrder.erc1155TokenId,
params.buyAmount,
address(0)
);
}
/// @dev Checks whether the given signature is valid for the
/// the given ERC1155 order. Reverts if not.
/// @param order The ERC1155 order.
/// @param signature The signature to validate.
function validateERC1155OrderSignature(
LibNFTOrder.ERC1155Order memory order,
LibSignature.Signature memory signature
)
public
override
view
{
bytes32 orderHash = getERC1155OrderHash(order);
_validateOrderSignature(orderHash, signature, order.maker);
}
/// @dev Validates that the given signature is valid for the
/// given maker and order hash. Reverts if the signature
/// is not valid.
/// @param orderHash The hash of the order that was signed.
/// @param signature The signature to check.
/// @param maker The maker of the order.
function _validateOrderSignature(
bytes32 orderHash,
LibSignature.Signature memory signature,
address maker
)
internal
override
view
{
if (signature.signatureType == LibSignature.SignatureType.PRESIGNED) {
// Check if order hash has been pre-signed by the maker.
bool isPreSigned = LibERC1155OrdersStorage.getStorage()
.orderState[orderHash].preSigned;
if (!isPreSigned) {
LibNFTOrdersRichErrors.InvalidSignerError(maker, address(0)).rrevert();
}
} else {
address signer = LibSignature.getSignerOfHash(orderHash, signature);
if (signer != maker) {
LibNFTOrdersRichErrors.InvalidSignerError(maker, signer).rrevert();
}
}
}
/// @dev Transfers an NFT asset.
/// @param token The address of the NFT contract.
/// @param from The address currently holding the asset.
/// @param to The address to transfer the asset to.
/// @param tokenId The ID of the asset to transfer.
/// @param amount The amount of the asset to transfer. Always
/// 1 for ERC721 assets.
function _transferNFTAssetFrom(
address token,
address from,
address to,
uint256 tokenId,
uint256 amount
)
internal
override
{
_transferERC1155AssetFrom(IERC1155Token(token), from, to, tokenId, amount);
}
/// @dev Updates storage to indicate that the given order
/// has been filled by the given amount.
/// @param orderHash The hash of `order`.
/// @param fillAmount The amount (denominated in the NFT asset)
/// that the order has been filled by.
function _updateOrderState(
LibNFTOrder.NFTOrder memory /* order */,
bytes32 orderHash,
uint128 fillAmount
)
internal
override
{
LibERC1155OrdersStorage.Storage storage stor = LibERC1155OrdersStorage.getStorage();
uint128 filledAmount = stor.orderState[orderHash].filledAmount;
// Filled amount should never overflow 128 bits
assert(filledAmount + fillAmount > filledAmount);
stor.orderState[orderHash].filledAmount = filledAmount + fillAmount;
}
/// @dev If the given order is buying an ERC1155 asset, checks
/// whether or not the given token ID satisfies the required
/// properties specified in the order. If the order does not
/// specify any properties, this function instead checks
/// whether the given token ID matches the ID in the order.
/// Reverts if any checks fail, or if the order is selling
/// an ERC1155 asset.
/// @param order The ERC1155 order.
/// @param erc1155TokenId The ID of the ERC1155 asset.
function validateERC1155OrderProperties(
LibNFTOrder.ERC1155Order memory order,
uint256 erc1155TokenId
)
public
override
view
{
_validateOrderProperties(
order.asNFTOrder(),
erc1155TokenId
);
}
/// @dev Get the order info for an ERC1155 order.
/// @param order The ERC1155 order.
/// @return orderInfo Info about the order.
function getERC1155OrderInfo(LibNFTOrder.ERC1155Order memory order)
public
override
view
returns (LibNFTOrder.OrderInfo memory orderInfo)
{
orderInfo.orderAmount = order.erc1155TokenAmount;
orderInfo.orderHash = getERC1155OrderHash(order);
// Only buy orders with `erc1155TokenId` == 0 can be property
// orders.
if (order.erc1155TokenProperties.length > 0 &&
(order.direction != LibNFTOrder.TradeDirection.BUY_NFT ||
order.erc1155TokenId != 0))
{
orderInfo.status = LibNFTOrder.OrderStatus.INVALID;
return orderInfo;
}
// Buy orders cannot use ETH as the ERC20 token, since ETH cannot be
// transferred from the buyer by a contract.
if (order.direction == LibNFTOrder.TradeDirection.BUY_NFT &&
address(order.erc20Token) == NATIVE_TOKEN_ADDRESS)
{
orderInfo.status = LibNFTOrder.OrderStatus.INVALID;
return orderInfo;
}
// Check for expiry.
if (order.expiry <= block.timestamp) {
orderInfo.status = LibNFTOrder.OrderStatus.EXPIRED;
return orderInfo;
}
{
LibERC1155OrdersStorage.Storage storage stor =
LibERC1155OrdersStorage.getStorage();
LibERC1155OrdersStorage.OrderState storage orderState =
stor.orderState[orderInfo.orderHash];
orderInfo.remainingAmount = order.erc1155TokenAmount
.safeSub128(orderState.filledAmount);
// `orderCancellationByMaker` is indexed by maker and nonce.
uint256 orderCancellationBitVector =
stor.orderCancellationByMaker[order.maker][uint248(order.nonce >> 8)];
// The bitvector is indexed by the lower 8 bits of the nonce.
uint256 flag = 1 << (order.nonce & 255);
if (orderInfo.remainingAmount == 0 ||
orderCancellationBitVector & flag != 0)
{
orderInfo.status = LibNFTOrder.OrderStatus.UNFILLABLE;
return orderInfo;
}
}
// Otherwise, the order is fillable.
orderInfo.status = LibNFTOrder.OrderStatus.FILLABLE;
}
/// @dev Get the order info for an NFT order.
/// @param order The NFT order.
/// @return orderInfo Info about the order.
function _getOrderInfo(LibNFTOrder.NFTOrder memory order)
internal
override
view
returns (LibNFTOrder.OrderInfo memory orderInfo)
{
return getERC1155OrderInfo(order.asERC1155Order());
}
/// @dev Get the EIP-712 hash of an ERC1155 order.
/// @param order The ERC1155 order.
/// @return orderHash The order hash.
function getERC1155OrderHash(LibNFTOrder.ERC1155Order memory order)
public
override
view
returns (bytes32 orderHash)
{
return _getEIP712Hash(LibNFTOrder.getERC1155OrderStructHash(order));
}
}

View File

@@ -0,0 +1,931 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../fixins/FixinERC721Spender.sol";
import "../../migrations/LibMigrate.sol";
import "../../storage/LibERC721OrdersStorage.sol";
import "../interfaces/IFeature.sol";
import "../interfaces/IERC721OrdersFeature.sol";
import "../libs/LibNFTOrder.sol";
import "../libs/LibSignature.sol";
import "./NFTOrders.sol";
/// @dev Feature for interacting with ERC721 orders.
contract ERC721OrdersFeature is
IFeature,
IERC721OrdersFeature,
FixinERC721Spender,
NFTOrders
{
using LibSafeMathV06 for uint256;
using LibNFTOrder for LibNFTOrder.ERC721Order;
using LibNFTOrder for LibNFTOrder.NFTOrder;
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "ERC721Orders";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev The magic return value indicating the success of a `onERC721Received`.
bytes4 private constant ERC721_RECEIVED_MAGIC_BYTES = this.onERC721Received.selector;
constructor(address zeroExAddress, IEtherTokenV06 weth)
public
NFTOrders(zeroExAddress, weth)
{}
/// @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.sellERC721.selector);
_registerFeatureFunction(this.buyERC721.selector);
_registerFeatureFunction(this.cancelERC721Order.selector);
_registerFeatureFunction(this.batchBuyERC721s.selector);
_registerFeatureFunction(this.matchERC721Orders.selector);
_registerFeatureFunction(this.batchMatchERC721Orders.selector);
_registerFeatureFunction(this.onERC721Received.selector);
_registerFeatureFunction(this.preSignERC721Order.selector);
_registerFeatureFunction(this.validateERC721OrderSignature.selector);
_registerFeatureFunction(this.validateERC721OrderProperties.selector);
_registerFeatureFunction(this.getERC721OrderStatus.selector);
_registerFeatureFunction(this.getERC721OrderHash.selector);
_registerFeatureFunction(this.getERC721OrderStatusBitVector.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Sells an ERC721 asset to fill the given order.
/// @param buyOrder The ERC721 buy order.
/// @param signature The order signature from the maker.
/// @param erc721TokenId The ID of the ERC721 asset being
/// sold. If the given order specifies properties,
/// the asset must satisfy those properties. Otherwise,
/// it must equal the tokenId in the order.
/// @param unwrapNativeToken If this parameter is true and the
/// ERC20 token of the order is e.g. WETH, unwraps the
/// token before transferring it to the taker.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC721OrderCallback` on `msg.sender` after
/// the ERC20 tokens have been transferred to `msg.sender`
/// but before transferring the ERC721 asset to the buyer.
function sellERC721(
LibNFTOrder.ERC721Order memory buyOrder,
LibSignature.Signature memory signature,
uint256 erc721TokenId,
bool unwrapNativeToken,
bytes memory callbackData
)
public
override
{
_sellERC721(
buyOrder,
signature,
erc721TokenId,
unwrapNativeToken,
msg.sender, // taker
msg.sender, // owner
callbackData
);
}
/// @dev Buys an ERC721 asset by filling the given order.
/// @param sellOrder The ERC721 sell order.
/// @param signature The order signature.
/// @param callbackData If this parameter is non-zero, invokes
/// `zeroExERC721OrderCallback` on `msg.sender` after
/// the ERC721 asset has been transferred to `msg.sender`
/// but before transferring the ERC20 tokens to the seller.
/// Native tokens acquired during the callback can be used
/// to fill the order.
function buyERC721(
LibNFTOrder.ERC721Order memory sellOrder,
LibSignature.Signature memory signature,
bytes memory callbackData
)
public
override
payable
{
uint256 ethBalanceBefore = address(this).balance
.safeSub(msg.value);
_buyERC721(
sellOrder,
signature,
msg.value,
callbackData
);
uint256 ethBalanceAfter = address(this).balance;
// Cannot use pre-existing ETH balance
if (ethBalanceAfter < ethBalanceBefore) {
LibNFTOrdersRichErrors.OverspentEthError(
msg.value + (ethBalanceBefore - ethBalanceAfter),
msg.value
).rrevert();
}
// Refund
_transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
}
/// @dev Cancel a single ERC721 order by its nonce. The caller
/// should be the maker of the order. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonce The order nonce.
function cancelERC721Order(uint256 orderNonce)
public
override
{
// Mark order as cancelled
_setOrderStatusBit(msg.sender, orderNonce);
emit ERC721OrderCancelled(msg.sender, orderNonce);
}
/// @dev Cancel multiple ERC721 orders by their nonces. The caller
/// should be the maker of the orders. Silently succeeds if
/// an order with the same nonce has already been filled or
/// cancelled.
/// @param orderNonces The order nonces.
function batchCancelERC721Orders(uint256[] calldata orderNonces)
external
override
{
for (uint256 i = 0; i < orderNonces.length; i++) {
cancelERC721Order(orderNonces[i]);
}
}
/// @dev Buys multiple ERC721 assets by filling the
/// given orders.
/// @param sellOrders The ERC721 sell orders.
/// @param signatures The order signatures.
/// @param revertIfIncomplete If true, reverts if this
/// function fails to fill any individual order.
/// @param callbackData The data (if any) to pass to the taker
/// callback for each order. Refer to the `callbackData`
/// parameter to for `buyERC721`.
/// @return successes An array of booleans corresponding to whether
/// each order in `orders` was successfully filled.
function batchBuyERC721s(
LibNFTOrder.ERC721Order[] memory sellOrders,
LibSignature.Signature[] memory signatures,
bytes[] memory callbackData,
bool revertIfIncomplete
)
public
override
payable
returns (bool[] memory successes)
{
require(
sellOrders.length == signatures.length &&
sellOrders.length == callbackData.length,
"ERC721OrdersFeature::batchBuyERC721s/ARRAY_LENGTH_MISMATCH"
);
successes = new bool[](sellOrders.length);
uint256 ethBalanceBefore = address(this).balance
.safeSub(msg.value);
if (revertIfIncomplete) {
for (uint256 i = 0; i < sellOrders.length; i++) {
// Will revert if _buyERC721 reverts.
_buyERC721(
sellOrders[i],
signatures[i],
address(this).balance.safeSub(ethBalanceBefore),
callbackData[i]
);
successes[i] = true;
}
} else {
for (uint256 i = 0; i < sellOrders.length; i++) {
// Delegatecall `_buyERC721` to swallow reverts while
// preserving execution context.
// Note that `_buyERC721` is a public function but should _not_
// be registered in the Exchange Proxy.
(successes[i], ) = _implementation.delegatecall(
abi.encodeWithSelector(
this._buyERC721.selector,
sellOrders[i],
signatures[i],
address(this).balance.safeSub(ethBalanceBefore), // Remaining ETH available
callbackData[i]
)
);
}
}
// Cannot use pre-existing ETH balance
uint256 ethBalanceAfter = address(this).balance;
if (ethBalanceAfter < ethBalanceBefore) {
LibNFTOrdersRichErrors.OverspentEthError(
msg.value + (ethBalanceBefore - ethBalanceAfter),
msg.value
).rrevert();
}
// Refund
_transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
}
/// @dev Matches a pair of complementary orders that have
/// a non-negative spread. Each order is filled at
/// their respective price, and the matcher receives
/// a profit denominated in the ERC20 token.
/// @param sellOrder Order selling an ERC721 asset.
/// @param buyOrder Order buying an ERC721 asset.
/// @param sellOrderSignature Signature for the sell order.
/// @param buyOrderSignature Signature for the buy order.
/// @return profit The amount of profit earned by the caller
/// of this function (denominated in the ERC20 token
/// of the matched orders).
function matchERC721Orders(
LibNFTOrder.ERC721Order memory sellOrder,
LibNFTOrder.ERC721Order memory buyOrder,
LibSignature.Signature memory sellOrderSignature,
LibSignature.Signature memory buyOrderSignature
)
public
override
returns (uint256 profit)
{
// The ERC721 tokens must match
if (sellOrder.erc721Token != buyOrder.erc721Token) {
LibNFTOrdersRichErrors.ERC721TokenMismatchError(
address(sellOrder.erc721Token),
address(buyOrder.erc721Token)
).rrevert();
}
LibNFTOrder.NFTOrder memory sellNFTOrder = sellOrder.asNFTOrder();
LibNFTOrder.NFTOrder memory buyNFTOrder = buyOrder.asNFTOrder();
{
LibNFTOrder.OrderInfo memory sellOrderInfo = _getOrderInfo(sellNFTOrder);
LibNFTOrder.OrderInfo memory buyOrderInfo = _getOrderInfo(buyNFTOrder);
_validateSellOrder(
sellNFTOrder,
sellOrderSignature,
sellOrderInfo,
buyOrder.maker
);
_validateBuyOrder(
buyNFTOrder,
buyOrderSignature,
buyOrderInfo,
sellOrder.maker,
sellOrder.erc721TokenId
);
// Mark both orders as filled.
_updateOrderState(sellNFTOrder, sellOrderInfo.orderHash, 1);
_updateOrderState(buyNFTOrder, buyOrderInfo.orderHash, 1);
}
// The buyer must be willing to pay at least the amount that the
// seller is asking.
if (buyOrder.erc20TokenAmount < sellOrder.erc20TokenAmount) {
LibNFTOrdersRichErrors.NegativeSpreadError(
sellOrder.erc20TokenAmount,
buyOrder.erc20TokenAmount
).rrevert();
}
// The difference in ERC20 token amounts is the spread.
uint256 spread = buyOrder.erc20TokenAmount - sellOrder.erc20TokenAmount;
// Transfer the ERC721 asset from seller to buyer.
_transferERC721AssetFrom(
sellOrder.erc721Token,
sellOrder.maker,
buyOrder.maker,
sellOrder.erc721TokenId
);
// Handle the ERC20 side of the order:
if (
address(sellOrder.erc20Token) == NATIVE_TOKEN_ADDRESS &&
buyOrder.erc20Token == WETH
) {
// The sell order specifies ETH, while the buy order specifies WETH.
// The orders are still compatible with one another, but we'll have
// to unwrap the WETH on behalf of the buyer.
// Step 1: Transfer WETH from the buyer to the EP.
// Note that we transfer `buyOrder.erc20TokenAmount`, which
// is the amount the buyer signaled they are willing to pay
// for the ERC721 asset, which may be more than the seller's
// ask.
_transferERC20TokensFrom(
WETH,
buyOrder.maker,
address(this),
buyOrder.erc20TokenAmount
);
// Step 2: Unwrap the WETH into ETH. We unwrap the entire
// `buyOrder.erc20TokenAmount`.
// The ETH will be used for three purposes:
// - To pay the seller
// - To pay fees for the sell order
// - Any remaining ETH will be sent to
// `msg.sender` as profit.
WETH.withdraw(buyOrder.erc20TokenAmount);
// Step 3: Pay the seller (in ETH).
_transferEth(payable(sellOrder.maker), sellOrder.erc20TokenAmount);
// Step 4: Pay fees for the buy order. Note that these are paid
// in _WETH_ by the _buyer_. By signing the buy order, the
// buyer signals that they are willing to spend a total
// of `erc20TokenAmount` _plus_ fees, all denominated in
// the `erc20Token`, which in this case is WETH.
_payFees(
buyNFTOrder,
buyOrder.maker, // payer
1, // fillAmount
1, // orderAmount
false // useNativeToken
);
// Step 5: Pay fees for the sell order. The `erc20Token` of the
// sell order is ETH, so the fees are paid out in ETH.
// There should be `spread` wei of ETH remaining in the
// EP at this point, which we will use ETH to pay the
// sell order fees.
uint256 sellOrderFees = _payFees(
sellNFTOrder,
address(this), // payer
1, // fillAmount
1, // orderAmount
true // useNativeToken
);
// Step 6: The spread must be enough to cover the sell order fees.
// If not, either `_payFees` will have reverted, or we
// have spent ETH that was in the EP before this
// `matchERC721Orders` call, which we disallow.
if (spread < sellOrderFees) {
LibNFTOrdersRichErrors.SellOrderFeesExceedSpreadError(
sellOrderFees,
spread
).rrevert();
}
// Step 7: The spread less the sell order fees is the amount of ETH
// remaining in the EP that can be sent to `msg.sender` as
// the profit from matching these two orders.
profit = spread - sellOrderFees;
if (profit > 0) {
_transferEth(msg.sender, profit);
}
} else {
// ERC20 tokens must match
if (sellOrder.erc20Token != buyOrder.erc20Token) {
LibNFTOrdersRichErrors.ERC20TokenMismatchError(
address(sellOrder.erc20Token),
address(buyOrder.erc20Token)
).rrevert();
}
// Step 1: Transfer the ERC20 token from the buyer to the seller.
// Note that we transfer `sellOrder.erc20TokenAmount`, which
// is at most `buyOrder.erc20TokenAmount`.
_transferERC20TokensFrom(
buyOrder.erc20Token,
buyOrder.maker,
sellOrder.maker,
sellOrder.erc20TokenAmount
);
// Step 2: Pay fees for the buy order. Note that these are paid
// by the buyer. By signing the buy order, the buyer signals
// that they are willing to spend a total of
// `buyOrder.erc20TokenAmount` _plus_ `buyOrder.fees`.
_payFees(
buyNFTOrder,
buyOrder.maker, // payer
1, // fillAmount
1, // orderAmount
false // useNativeToken
);
// Step 3: Pay fees for the sell order. These are paid by the buyer
// as well. After paying these fees, we may have taken more
// from the buyer than they agreed to in the buy order. If
// so, we revert in the following step.
uint256 sellOrderFees = _payFees(
sellNFTOrder,
buyOrder.maker, // payer
1, // fillAmount
1, // orderAmount
false // useNativeToken
);
// Step 4: The spread must be enough to cover the sell order fees.
// If not, `_payFees` will have taken more tokens from the
// buyer than they had agreed to in the buy order, in which
// case we revert here.
if (spread < sellOrderFees) {
LibNFTOrdersRichErrors.SellOrderFeesExceedSpreadError(
sellOrderFees,
spread
).rrevert();
}
// Step 5: We calculate the profit as:
// profit = buyOrder.erc20TokenAmount - sellOrder.erc20TokenAmount - sellOrderFees
// = spread - sellOrderFees
// I.e. the buyer would've been willing to pay up to `profit`
// more to buy the asset, so instead that amount is sent to
// `msg.sender` as the profit from matching these two orders.
profit = spread - sellOrderFees;
if (profit > 0) {
_transferERC20TokensFrom(
buyOrder.erc20Token,
buyOrder.maker,
msg.sender,
profit
);
}
}
emit ERC721OrderFilled(
sellOrder.direction,
sellOrder.maker,
buyOrder.maker, // taker
sellOrder.nonce,
sellOrder.erc20Token,
sellOrder.erc20TokenAmount,
sellOrder.erc721Token,
sellOrder.erc721TokenId,
msg.sender
);
emit ERC721OrderFilled(
buyOrder.direction,
buyOrder.maker,
sellOrder.maker, // taker
buyOrder.nonce,
buyOrder.erc20Token,
buyOrder.erc20TokenAmount,
buyOrder.erc721Token,
sellOrder.erc721TokenId,
msg.sender
);
}
/// @dev Matches pairs of complementary orders that have
/// non-negative spreads. Each order is filled at
/// their respective price, and the matcher receives
/// a profit denominated in the ERC20 token.
/// @param sellOrders Orders selling ERC721 assets.
/// @param buyOrders Orders buying ERC721 assets.
/// @param sellOrderSignatures Signatures for the sell orders.
/// @param buyOrderSignatures Signatures for the buy orders.
/// @return profits The amount of profit earned by the caller
/// of this function for each pair of matched orders
/// (denominated in the ERC20 token of the order pair).
/// @return successes An array of booleans corresponding to
/// whether each pair of orders was successfully matched.
function batchMatchERC721Orders(
LibNFTOrder.ERC721Order[] memory sellOrders,
LibNFTOrder.ERC721Order[] memory buyOrders,
LibSignature.Signature[] memory sellOrderSignatures,
LibSignature.Signature[] memory buyOrderSignatures
)
public
override
returns (uint256[] memory profits, bool[] memory successes)
{
require(
sellOrders.length == buyOrders.length &&
sellOrderSignatures.length == buyOrderSignatures.length &&
sellOrders.length == sellOrderSignatures.length,
"ERC721OrdersFeature::batchMatchERC721Orders/ARRAY_LENGTH_MISMATCH"
);
profits = new uint256[](sellOrders.length);
successes = new bool[](sellOrders.length);
for (uint256 i = 0; i < sellOrders.length; i++) {
bytes memory returnData;
// Delegatecall `matchERC721Orders` to catch reverts while
// preserving execution context.
(successes[i], returnData) = _implementation.delegatecall(
abi.encodeWithSelector(
this.matchERC721Orders.selector,
sellOrders[i],
buyOrders[i],
sellOrderSignatures[i],
buyOrderSignatures[i]
)
);
if (successes[i]) {
// If the matching succeeded, record the profit.
(uint256 profit) = abi.decode(returnData, (uint256));
profits[i] = profit;
}
}
}
/// @dev Callback for the ERC721 `safeTransferFrom` function.
/// This callback can be used to sell an ERC721 asset if
/// a valid ERC721 order, signature and `unwrapNativeToken`
/// are encoded in `data`. This allows takers to sell their
/// ERC721 asset without first calling `setApprovalForAll`.
/// @param operator The address which called `safeTransferFrom`.
/// @param tokenId The ID of the asset being transferred.
/// @param data Additional data with no specified format. If a
/// valid ERC721 order, signature and `unwrapNativeToken`
/// are encoded in `data`, this function will try to fill
/// the order using the received asset.
/// @return success The selector of this function (0x150b7a02),
/// indicating that the callback succeeded.
function onERC721Received(
address operator,
address /* from */,
uint256 tokenId,
bytes calldata data
)
external
override
returns (bytes4 success)
{
// Decode the order, signature, and `unwrapNativeToken` from
// `data`. If `data` does not encode such parameters, this
// will throw.
(
LibNFTOrder.ERC721Order memory buyOrder,
LibSignature.Signature memory signature,
bool unwrapNativeToken
) = abi.decode(
data,
(LibNFTOrder.ERC721Order, LibSignature.Signature, bool)
);
// `onERC721Received` is called by the ERC721 token contract.
// Check that it matches the ERC721 token in the order.
if (msg.sender != address(buyOrder.erc721Token)) {
LibNFTOrdersRichErrors.ERC721TokenMismatchError(
msg.sender,
address(buyOrder.erc721Token)
).rrevert();
}
_sellERC721(
buyOrder,
signature,
tokenId,
unwrapNativeToken,
operator, // taker
address(this), // owner (we hold the NFT currently)
new bytes(0) // No taker callback
);
return ERC721_RECEIVED_MAGIC_BYTES;
}
/// @dev Approves an ERC721 order on-chain. After pre-signing
/// the order, the `PRESIGNED` signature type will become
/// valid for that order and signer.
/// @param order An ERC721 order.
function preSignERC721Order(LibNFTOrder.ERC721Order memory order)
public
override
{
require(
order.maker == msg.sender,
"ERC721OrdersFeature::preSignERC721Order/ONLY_MAKER"
);
bytes32 orderHash = getERC721OrderHash(order);
LibERC721OrdersStorage.getStorage().preSigned[orderHash] = true;
emit ERC721OrderPreSigned(
order.direction,
order.maker,
order.taker,
order.expiry,
order.nonce,
order.erc20Token,
order.erc20TokenAmount,
order.fees,
order.erc721Token,
order.erc721TokenId,
order.erc721TokenProperties
);
}
// Core settlement logic for selling an ERC721 asset.
// Used by `sellERC721` and `onERC721Received`.
function _sellERC721(
LibNFTOrder.ERC721Order memory buyOrder,
LibSignature.Signature memory signature,
uint256 erc721TokenId,
bool unwrapNativeToken,
address taker,
address currentNftOwner,
bytes memory takerCallbackData
)
private
{
_sellNFT(
buyOrder.asNFTOrder(),
signature,
SellParams(
1, // sell amount
erc721TokenId,
unwrapNativeToken,
taker,
currentNftOwner,
takerCallbackData
)
);
emit ERC721OrderFilled(
buyOrder.direction,
buyOrder.maker,
taker,
buyOrder.nonce,
buyOrder.erc20Token,
buyOrder.erc20TokenAmount,
buyOrder.erc721Token,
erc721TokenId,
address(0)
);
}
// Core settlement logic for buying an ERC721 asset.
// Used by `buyERC721` and `batchBuyERC721s`.
function _buyERC721(
LibNFTOrder.ERC721Order memory sellOrder,
LibSignature.Signature memory signature,
uint256 ethAvailable,
bytes memory takerCallbackData
)
public
payable
{
_buyNFT(
sellOrder.asNFTOrder(),
signature,
BuyParams(
1, // buy amount
ethAvailable,
takerCallbackData
)
);
emit ERC721OrderFilled(
sellOrder.direction,
sellOrder.maker,
msg.sender,
sellOrder.nonce,
sellOrder.erc20Token,
sellOrder.erc20TokenAmount,
sellOrder.erc721Token,
sellOrder.erc721TokenId,
address(0)
);
}
/// @dev Checks whether the given signature is valid for the
/// the given ERC721 order. Reverts if not.
/// @param order The ERC721 order.
/// @param signature The signature to validate.
function validateERC721OrderSignature(
LibNFTOrder.ERC721Order memory order,
LibSignature.Signature memory signature
)
public
override
view
{
bytes32 orderHash = getERC721OrderHash(order);
_validateOrderSignature(orderHash, signature, order.maker);
}
/// @dev Validates that the given signature is valid for the
/// given maker and order hash. Reverts if the signature
/// is not valid.
/// @param orderHash The hash of the order that was signed.
/// @param signature The signature to check.
/// @param maker The maker of the order.
function _validateOrderSignature(
bytes32 orderHash,
LibSignature.Signature memory signature,
address maker
)
internal
override
view
{
if (signature.signatureType == LibSignature.SignatureType.PRESIGNED) {
// Check if order hash has been pre-signed by the maker.
bool isPreSigned = LibERC721OrdersStorage.getStorage().preSigned[orderHash];
if (!isPreSigned) {
LibNFTOrdersRichErrors.InvalidSignerError(maker, address(0)).rrevert();
}
} else {
address signer = LibSignature.getSignerOfHash(orderHash, signature);
if (signer != maker) {
LibNFTOrdersRichErrors.InvalidSignerError(maker, signer).rrevert();
}
}
}
/// @dev Transfers an NFT asset.
/// @param token The address of the NFT contract.
/// @param from The address currently holding the asset.
/// @param to The address to transfer the asset to.
/// @param tokenId The ID of the asset to transfer.
/// @param amount The amount of the asset to transfer. Always
/// 1 for ERC721 assets.
function _transferNFTAssetFrom(
address token,
address from,
address to,
uint256 tokenId,
uint256 amount
)
internal
override
{
assert(amount == 1);
_transferERC721AssetFrom(IERC721Token(token), from, to, tokenId);
}
/// @dev Updates storage to indicate that the given order
/// has been filled by the given amount.
/// @param order The order that has been filled.
/// @param fillAmount The amount (denominated in the NFT asset)
/// that the order has been filled by.
function _updateOrderState(
LibNFTOrder.NFTOrder memory order,
bytes32 /* orderHash */,
uint128 fillAmount
)
internal
override
{
assert(fillAmount == 1);
_setOrderStatusBit(order.maker, order.nonce);
}
function _setOrderStatusBit(address maker, uint256 nonce)
private
{
// The bitvector is indexed by the lower 8 bits of the nonce.
uint256 flag = 1 << (nonce & 255);
// Update order status bit vector to indicate that the given order
// has been cancelled/filled by setting the designated bit to 1.
LibERC721OrdersStorage.getStorage().orderStatusByMaker
[maker][uint248(nonce >> 8)] |= flag;
}
/// @dev If the given order is buying an ERC721 asset, checks
/// whether or not the given token ID satisfies the required
/// properties specified in the order. If the order does not
/// specify any properties, this function instead checks
/// whether the given token ID matches the ID in the order.
/// Reverts if any checks fail, or if the order is selling
/// an ERC721 asset.
/// @param order The ERC721 order.
/// @param erc721TokenId The ID of the ERC721 asset.
function validateERC721OrderProperties(
LibNFTOrder.ERC721Order memory order,
uint256 erc721TokenId
)
public
override
view
{
_validateOrderProperties(
order.asNFTOrder(),
erc721TokenId
);
}
/// @dev Get the current status of an ERC721 order.
/// @param order The ERC721 order.
/// @return status The status of the order.
function getERC721OrderStatus(LibNFTOrder.ERC721Order memory order)
public
override
view
returns (LibNFTOrder.OrderStatus status)
{
// Only buy orders with `erc721TokenId` == 0 can be property
// orders.
if (order.erc721TokenProperties.length > 0 &&
(order.direction != LibNFTOrder.TradeDirection.BUY_NFT ||
order.erc721TokenId != 0))
{
return LibNFTOrder.OrderStatus.INVALID;
}
// Buy orders cannot use ETH as the ERC20 token, since ETH cannot be
// transferred from the buyer by a contract.
if (order.direction == LibNFTOrder.TradeDirection.BUY_NFT &&
address(order.erc20Token) == NATIVE_TOKEN_ADDRESS)
{
return LibNFTOrder.OrderStatus.INVALID;
}
// Check for expiry.
if (order.expiry <= block.timestamp) {
return LibNFTOrder.OrderStatus.EXPIRED;
}
// Check `orderStatusByMaker` state variable to see if the order
// has been cancelled or previously filled.
LibERC721OrdersStorage.Storage storage stor =
LibERC721OrdersStorage.getStorage();
// `orderStatusByMaker` is indexed by maker and nonce.
uint256 orderStatusBitVector =
stor.orderStatusByMaker[order.maker][uint248(order.nonce >> 8)];
// The bitvector is indexed by the lower 8 bits of the nonce.
uint256 flag = 1 << (order.nonce & 255);
// If the designated bit is set, the order has been cancelled or
// previously filled, so it is now unfillable.
if (orderStatusBitVector & flag != 0) {
return LibNFTOrder.OrderStatus.UNFILLABLE;
}
// Otherwise, the order is fillable.
return LibNFTOrder.OrderStatus.FILLABLE;
}
/// @dev Get the order info for an NFT order.
/// @param order The NFT order.
/// @return orderInfo Info about the order.
function _getOrderInfo(LibNFTOrder.NFTOrder memory order)
internal
override
view
returns (LibNFTOrder.OrderInfo memory orderInfo)
{
LibNFTOrder.ERC721Order memory erc721Order = order.asERC721Order();
orderInfo.orderHash = getERC721OrderHash(erc721Order);
orderInfo.status = getERC721OrderStatus(erc721Order);
orderInfo.orderAmount = 1;
orderInfo.remainingAmount = orderInfo.status == LibNFTOrder.OrderStatus.FILLABLE ? 1 : 0;
}
/// @dev Get the EIP-712 hash of an ERC721 order.
/// @param order The ERC721 order.
/// @return orderHash The order hash.
function getERC721OrderHash(LibNFTOrder.ERC721Order memory order)
public
override
view
returns (bytes32 orderHash)
{
return _getEIP712Hash(LibNFTOrder.getERC721OrderStructHash(order));
}
/// @dev Get the order status bit vector for the given
/// maker address and nonce range.
/// @param maker The maker of the order.
/// @param nonceRange Order status bit vectors are indexed
/// by maker address and the upper 248 bits of the
/// order nonce. We define `nonceRange` to be these
/// 248 bits.
/// @return bitVector The order status bit vector for the
/// given maker and nonce range.
function getERC721OrderStatusBitVector(address maker, uint248 nonceRange)
external
override
view
returns (uint256 bitVector)
{
LibERC721OrdersStorage.Storage storage stor =
LibERC721OrdersStorage.getStorage();
return stor.orderStatusByMaker[maker][nonceRange];
}
}

View File

@@ -0,0 +1,615 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/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 "../../errors/LibNFTOrdersRichErrors.sol";
import "../../fixins/FixinCommon.sol";
import "../../fixins/FixinEIP712.sol";
import "../../fixins/FixinTokenSpender.sol";
import "../../migrations/LibMigrate.sol";
import "../../vendor/IFeeRecipient.sol";
import "../../vendor/ITakerCallback.sol";
import "../libs/LibSignature.sol";
import "../libs/LibNFTOrder.sol";
/// @dev Abstract base contract inherited by ERC721OrdersFeature and NFTOrders
abstract contract NFTOrders is
FixinCommon,
FixinEIP712,
FixinTokenSpender
{
using LibSafeMathV06 for uint256;
/// @dev Native token pseudo-address.
address constant internal NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev The WETH token contract.
IEtherTokenV06 internal immutable WETH;
/// @dev The magic return value indicating the success of a `receiveZeroExFeeCallback`.
bytes4 private constant FEE_CALLBACK_MAGIC_BYTES = IFeeRecipient.receiveZeroExFeeCallback.selector;
/// @dev The magic return value indicating the success of a `zeroExTakerCallback`.
bytes4 private constant TAKER_CALLBACK_MAGIC_BYTES = ITakerCallback.zeroExTakerCallback.selector;
constructor(address zeroExAddress, IEtherTokenV06 weth)
public
FixinEIP712(zeroExAddress)
{
WETH = weth;
}
struct SellParams {
uint128 sellAmount;
uint256 tokenId;
bool unwrapNativeToken;
address taker;
address currentNftOwner;
bytes takerCallbackData;
}
struct BuyParams {
uint128 buyAmount;
uint256 ethAvailable;
bytes takerCallbackData;
}
// Core settlement logic for selling an NFT asset.
function _sellNFT(
LibNFTOrder.NFTOrder memory buyOrder,
LibSignature.Signature memory signature,
SellParams memory params
)
internal
returns (uint256 erc20FillAmount)
{
LibNFTOrder.OrderInfo memory orderInfo = _getOrderInfo(buyOrder);
// Check that the order can be filled.
_validateBuyOrder(
buyOrder,
signature,
orderInfo,
params.taker,
params.tokenId
);
if (params.sellAmount > orderInfo.remainingAmount) {
LibNFTOrdersRichErrors.ExceedsRemainingOrderAmount(
orderInfo.remainingAmount,
params.sellAmount
).rrevert();
}
_updateOrderState(buyOrder, orderInfo.orderHash, params.sellAmount);
if (params.sellAmount == orderInfo.orderAmount) {
erc20FillAmount = buyOrder.erc20TokenAmount;
} else {
// Rounding favors the order maker.
erc20FillAmount = LibMathV06.getPartialAmountFloor(
params.sellAmount,
orderInfo.orderAmount,
buyOrder.erc20TokenAmount
);
}
if (params.unwrapNativeToken) {
// The ERC20 token must be WETH for it to be unwrapped.
if (buyOrder.erc20Token != WETH) {
LibNFTOrdersRichErrors.ERC20TokenMismatchError(
address(buyOrder.erc20Token),
address(WETH)
).rrevert();
}
// Transfer the WETH from the maker to the Exchange Proxy
// so we can unwrap it before sending it to the seller.
// TODO: Probably safe to just use WETH.transferFrom for some
// small gas savings
_transferERC20TokensFrom(
WETH,
buyOrder.maker,
address(this),
erc20FillAmount
);
// Unwrap WETH into ETH.
WETH.withdraw(erc20FillAmount);
// Send ETH to the seller.
_transferEth(payable(params.taker), erc20FillAmount);
} else {
// Transfer the ERC20 token from the buyer to the seller.
_transferERC20TokensFrom(
buyOrder.erc20Token,
buyOrder.maker,
params.taker,
erc20FillAmount
);
}
if (params.takerCallbackData.length > 0) {
require(
params.taker != address(this),
"NFTOrders::_sellNFT/CANNOT_CALLBACK_SELF"
);
// Invoke the callback
bytes4 callbackResult = ITakerCallback(params.taker)
.zeroExTakerCallback(orderInfo.orderHash, params.takerCallbackData);
// Check for the magic success bytes
require(
callbackResult == TAKER_CALLBACK_MAGIC_BYTES,
"NFTOrders::_sellNFT/CALLBACK_FAILED"
);
}
// Transfer the NFT asset to the buyer.
// If this function is called from the
// `onNFTReceived` callback the Exchange Proxy
// holds the asset. Otherwise, transfer it from
// the seller.
_transferNFTAssetFrom(
buyOrder.nft,
params.currentNftOwner,
buyOrder.maker,
params.tokenId,
params.sellAmount
);
// The buyer pays the order fees.
_payFees(
buyOrder,
buyOrder.maker,
params.sellAmount,
orderInfo.orderAmount,
false
);
}
// Core settlement logic for buying an NFT asset.
function _buyNFT(
LibNFTOrder.NFTOrder memory sellOrder,
LibSignature.Signature memory signature,
BuyParams memory params
)
internal
returns (uint256 erc20FillAmount)
{
LibNFTOrder.OrderInfo memory orderInfo = _getOrderInfo(sellOrder);
// Check that the order can be filled.
_validateSellOrder(
sellOrder,
signature,
orderInfo,
msg.sender
);
if (params.buyAmount > orderInfo.remainingAmount) {
LibNFTOrdersRichErrors.ExceedsRemainingOrderAmount(
orderInfo.remainingAmount,
params.buyAmount
).rrevert();
}
_updateOrderState(sellOrder, orderInfo.orderHash, params.buyAmount);
if (params.buyAmount == orderInfo.orderAmount) {
erc20FillAmount = sellOrder.erc20TokenAmount;
} else {
// Rounding favors the order maker.
erc20FillAmount = LibMathV06.getPartialAmountCeil(
params.buyAmount,
orderInfo.orderAmount,
sellOrder.erc20TokenAmount
);
}
// Transfer the NFT asset to the buyer (`msg.sender`).
_transferNFTAssetFrom(
sellOrder.nft,
sellOrder.maker,
msg.sender,
sellOrder.nftId,
params.buyAmount
);
uint256 ethAvailable = params.ethAvailable;
if (params.takerCallbackData.length > 0) {
require(
msg.sender != address(this),
"NFTOrders::_buyNFT/CANNOT_CALLBACK_SELF"
);
uint256 ethBalanceBeforeCallback = address(this).balance;
// Invoke the callback
bytes4 callbackResult = ITakerCallback(msg.sender)
.zeroExTakerCallback(orderInfo.orderHash, params.takerCallbackData);
// Update `ethAvailable` with amount acquired during
// the callback
ethAvailable = ethAvailable.safeAdd(
address(this).balance.safeSub(ethBalanceBeforeCallback)
);
// Check for the magic success bytes
require(
callbackResult == TAKER_CALLBACK_MAGIC_BYTES,
"NFTOrders::_buyNFT/CALLBACK_FAILED"
);
}
if (address(sellOrder.erc20Token) == NATIVE_TOKEN_ADDRESS) {
// Transfer ETH to the seller.
_transferEth(payable(sellOrder.maker), erc20FillAmount);
// Fees are paid from the EP's current balance of ETH.
_payEthFees(
sellOrder,
params.buyAmount,
orderInfo.orderAmount,
erc20FillAmount,
ethAvailable
);
} else if (sellOrder.erc20Token == WETH) {
// If there is enough ETH available, fill the WETH order
// (including fees) using that ETH.
// Otherwise, transfer WETH from the taker.
if (ethAvailable >= erc20FillAmount) {
// Wrap ETH.
WETH.deposit{value: erc20FillAmount}();
// TODO: Probably safe to just use WETH.transfer for some
// small gas savings
// Transfer WETH to the seller.
_transferERC20Tokens(
WETH,
sellOrder.maker,
erc20FillAmount
);
// Fees are paid from the EP's current balance of ETH.
_payEthFees(
sellOrder,
params.buyAmount,
orderInfo.orderAmount,
erc20FillAmount,
ethAvailable
);
} else {
// Transfer WETH from the buyer to the seller.
_transferERC20TokensFrom(
sellOrder.erc20Token,
msg.sender,
sellOrder.maker,
erc20FillAmount
);
// The buyer pays fees using WETH.
_payFees(
sellOrder,
msg.sender,
params.buyAmount,
orderInfo.orderAmount,
false
);
}
} else {
// Transfer ERC20 token from the buyer to the seller.
_transferERC20TokensFrom(
sellOrder.erc20Token,
msg.sender,
sellOrder.maker,
erc20FillAmount
);
// The buyer pays fees.
_payFees(
sellOrder,
msg.sender,
params.buyAmount,
orderInfo.orderAmount,
false
);
}
}
function _validateSellOrder(
LibNFTOrder.NFTOrder memory sellOrder,
LibSignature.Signature memory signature,
LibNFTOrder.OrderInfo memory orderInfo,
address taker
)
internal
view
{
// Order must be selling the NFT asset.
require(
sellOrder.direction == LibNFTOrder.TradeDirection.SELL_NFT,
"NFTOrders::_validateSellOrder/WRONG_TRADE_DIRECTION"
);
// Taker must match the order taker, if one is specified.
if (sellOrder.taker != address(0) && sellOrder.taker != taker) {
LibNFTOrdersRichErrors.OnlyTakerError(taker, sellOrder.taker).rrevert();
}
// Check that the order is valid and has not expired, been cancelled,
// or been filled.
if (orderInfo.status != LibNFTOrder.OrderStatus.FILLABLE) {
LibNFTOrdersRichErrors.OrderNotFillableError(
sellOrder.maker,
sellOrder.nonce,
uint8(orderInfo.status)
).rrevert();
}
// Check the signature.
_validateOrderSignature(orderInfo.orderHash, signature, sellOrder.maker);
}
function _validateBuyOrder(
LibNFTOrder.NFTOrder memory buyOrder,
LibSignature.Signature memory signature,
LibNFTOrder.OrderInfo memory orderInfo,
address taker,
uint256 tokenId
)
internal
view
{
// Order must be buying the NFT asset.
require(
buyOrder.direction == LibNFTOrder.TradeDirection.BUY_NFT,
"NFTOrders::_validateBuyOrder/WRONG_TRADE_DIRECTION"
);
// The ERC20 token cannot be ETH.
require(
address(buyOrder.erc20Token) != NATIVE_TOKEN_ADDRESS,
"NFTOrders::_validateBuyOrder/NATIVE_TOKEN_NOT_ALLOWED"
);
// Taker must match the order taker, if one is specified.
if (buyOrder.taker != address(0) && buyOrder.taker != taker) {
LibNFTOrdersRichErrors.OnlyTakerError(taker, buyOrder.taker).rrevert();
}
// Check that the order is valid and has not expired, been cancelled,
// or been filled.
if (orderInfo.status != LibNFTOrder.OrderStatus.FILLABLE) {
LibNFTOrdersRichErrors.OrderNotFillableError(
buyOrder.maker,
buyOrder.nonce,
uint8(orderInfo.status)
).rrevert();
}
// Check that the asset with the given token ID satisfies the properties
// specified by the order.
_validateOrderProperties(buyOrder, tokenId);
// Check the signature.
_validateOrderSignature(orderInfo.orderHash, signature, buyOrder.maker);
}
function _payEthFees(
LibNFTOrder.NFTOrder memory order,
uint128 fillAmount,
uint128 orderAmount,
uint256 ethSpent,
uint256 ethAvailable
)
private
{
// Pay fees using ETH.
uint256 ethFees = _payFees(
order,
address(this),
fillAmount,
orderAmount,
true
);
// Update amount of ETH spent.
ethSpent = ethSpent.safeAdd(ethFees);
if (ethSpent > ethAvailable) {
LibNFTOrdersRichErrors.OverspentEthError(
ethSpent,
ethAvailable
).rrevert();
}
}
function _payFees(
LibNFTOrder.NFTOrder memory order,
address payer,
uint128 fillAmount,
uint128 orderAmount,
bool useNativeToken
)
internal
returns (uint256 totalFeesPaid)
{
// Make assertions about ETH case
if (useNativeToken) {
assert(payer == address(this));
assert(
order.erc20Token == WETH ||
address(order.erc20Token) == NATIVE_TOKEN_ADDRESS
);
}
for (uint256 i = 0; i < order.fees.length; i++) {
LibNFTOrder.Fee memory fee = order.fees[i];
require(
fee.recipient != address(this),
"NFTOrders::_payFees/RECIPIENT_CANNOT_BE_EXCHANGE_PROXY"
);
uint256 feeFillAmount;
if (fillAmount == orderAmount) {
feeFillAmount = fee.amount;
} else {
// Round against the fee recipient
feeFillAmount = LibMathV06.getPartialAmountFloor(
fillAmount,
orderAmount,
fee.amount
);
}
if (feeFillAmount == 0) {
continue;
}
if (useNativeToken) {
// Transfer ETH to the fee recipient.
_transferEth(payable(fee.recipient), feeFillAmount);
} else {
// Transfer ERC20 token from payer to recipient.
_transferERC20TokensFrom(
order.erc20Token,
payer,
fee.recipient,
feeFillAmount
);
}
// Note that the fee callback is _not_ called if zero
// `feeData` is provided. If `feeData` is provided, we assume
// the fee recipient is a contract that implements the
// `IFeeRecipient` interface.
if (fee.feeData.length > 0) {
// Invoke the callback
bytes4 callbackResult = IFeeRecipient(fee.recipient).receiveZeroExFeeCallback(
useNativeToken ? NATIVE_TOKEN_ADDRESS : address(order.erc20Token),
feeFillAmount,
fee.feeData
);
// Check for the magic success bytes
require(
callbackResult == FEE_CALLBACK_MAGIC_BYTES,
"NFTOrders::_payFees/CALLBACK_FAILED"
);
}
// Sum the fees paid
totalFeesPaid = totalFeesPaid.safeAdd(feeFillAmount);
}
}
/// @dev If the given order is buying an NFT asset, checks
/// whether or not the given token ID satisfies the required
/// properties specified in the order. If the order does not
/// specify any properties, this function instead checks
/// whether the given token ID matches the ID in the order.
/// Reverts if any checks fail, or if the order is selling
/// an NFT asset.
/// @param order The NFT order.
/// @param tokenId The ID of the NFT asset.
function _validateOrderProperties(
LibNFTOrder.NFTOrder memory order,
uint256 tokenId
)
internal
view
{
// Order must be buying an NFT asset to have properties.
require(
order.direction == LibNFTOrder.TradeDirection.BUY_NFT,
"NFTOrders::_validateOrderProperties/WRONG_TRADE_DIRECTION"
);
// If no properties are specified, check that the given
// `tokenId` matches the one specified in the order.
if (order.nftProperties.length == 0) {
if (tokenId != order.nftId) {
LibNFTOrdersRichErrors.TokenIdMismatchError(
tokenId,
order.nftId
).rrevert();
}
} else {
// Validate each property
for (uint256 i = 0; i < order.nftProperties.length; i++) {
LibNFTOrder.Property memory property = order.nftProperties[i];
// `address(0)` is interpreted as a no-op. Any token ID
// will satisfy a property with `propertyValidator == address(0)`.
if (address(property.propertyValidator) == address(0)) {
continue;
}
// Call the property validator and throw a descriptive error
// if the call reverts.
try property.propertyValidator.validateProperty(
order.nft,
tokenId,
property.propertyData
) {} catch (bytes memory errorData) {
LibNFTOrdersRichErrors.PropertyValidationFailedError(
address(property.propertyValidator),
order.nft,
tokenId,
property.propertyData,
errorData
).rrevert();
}
}
}
}
/// @dev Validates that the given signature is valid for the
/// given maker and order hash. Reverts if the signature
/// is not valid.
/// @param orderHash The hash of the order that was signed.
/// @param signature The signature to check.
/// @param maker The maker of the order.
function _validateOrderSignature(
bytes32 orderHash,
LibSignature.Signature memory signature,
address maker
)
internal
virtual
view;
/// @dev Transfers an NFT asset.
/// @param token The address of the NFT contract.
/// @param from The address currently holding the asset.
/// @param to The address to transfer the asset to.
/// @param tokenId The ID of the asset to transfer.
/// @param amount The amount of the asset to transfer. Always
/// 1 for ERC721 assets.
function _transferNFTAssetFrom(
address token,
address from,
address to,
uint256 tokenId,
uint256 amount
)
internal
virtual;
/// @dev Updates storage to indicate that the given order
/// has been filled by the given amount.
/// @param order The order that has been filled.
/// @param orderHash The hash of `order`.
/// @param fillAmount The amount (denominated in the NFT asset)
/// that the order has been filled by.
function _updateOrderState(
LibNFTOrder.NFTOrder memory order,
bytes32 orderHash,
uint128 fillAmount
)
internal
virtual;
/// @dev Get the order info for an NFT order.
/// @param order The NFT order.
/// @return orderInfo Info about the order.
function _getOrderInfo(LibNFTOrder.NFTOrder memory order)
internal
virtual
view
returns (LibNFTOrder.OrderInfo memory orderInfo);
}

View File

@@ -0,0 +1,79 @@
// 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;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../vendor/IERC1155Token.sol";
/// @dev Helpers for moving ERC1155 assets around.
abstract contract FixinERC1155Spender {
// Mask of the lower 20 bytes of a bytes32.
uint256 constant private ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff;
/// @dev Transfers an ERC1155 asset from `owner` to `to`.
/// @param token The address of the ERC1155 token contract.
/// @param owner The owner of the asset.
/// @param to The recipient of the asset.
/// @param tokenId The token ID of the asset to transfer.
/// @param amount The amount of the asset to transfer.
function _transferERC1155AssetFrom(
IERC1155Token token,
address owner,
address to,
uint256 tokenId,
uint256 amount
)
internal
{
require(address(token) != address(this), "FixinERC1155Spender/CANNOT_INVOKE_SELF");
assembly {
let ptr := mload(0x40) // free memory pointer
// selector for safeTransferFrom(address,address,uint256,uint256,bytes)
mstore(ptr, 0xf242432a00000000000000000000000000000000000000000000000000000000)
mstore(add(ptr, 0x04), and(owner, ADDRESS_MASK))
mstore(add(ptr, 0x24), and(to, ADDRESS_MASK))
mstore(add(ptr, 0x44), tokenId)
mstore(add(ptr, 0x64), amount)
mstore(add(ptr, 0x84), 0xa0)
mstore(add(ptr, 0xa4), 0)
let success := call(
gas(),
and(token, ADDRESS_MASK),
0,
ptr,
0xc4,
0,
0
)
if iszero(success) {
let rdsize := returndatasize()
returndatacopy(ptr, 0, rdsize)
revert(ptr, rdsize)
}
}
}
}

View File

@@ -0,0 +1,74 @@
// 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;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../vendor/IERC721Token.sol";
/// @dev Helpers for moving ERC721 assets around.
abstract contract FixinERC721Spender {
// Mask of the lower 20 bytes of a bytes32.
uint256 constant private ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff;
/// @dev Transfers an ERC721 asset from `owner` to `to`.
/// @param token The address of the ERC721 token contract.
/// @param owner The owner of the asset.
/// @param to The recipient of the asset.
/// @param tokenId The token ID of the asset to transfer.
function _transferERC721AssetFrom(
IERC721Token token,
address owner,
address to,
uint256 tokenId
)
internal
{
require(address(token) != address(this), "FixinERC721Spender/CANNOT_INVOKE_SELF");
assembly {
let ptr := mload(0x40) // free memory pointer
// selector for transferFrom(address,address,uint256)
mstore(ptr, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(ptr, 0x04), and(owner, ADDRESS_MASK))
mstore(add(ptr, 0x24), and(to, ADDRESS_MASK))
mstore(add(ptr, 0x44), tokenId)
let success := call(
gas(),
and(token, ADDRESS_MASK),
0,
ptr,
0x64,
0,
0
)
if iszero(success) {
let rdsize := returndatasize()
returndatacopy(ptr, 0, rdsize)
revert(ptr, rdsize)
}
}
}
}

View File

@@ -20,7 +20,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
@@ -141,6 +141,20 @@ abstract contract FixinTokenSpender {
}
}
/// @dev Transfers some amount of ETH to the given recipient and
/// reverts if the transfer fails.
/// @param recipient The recipient of the ETH.
/// @param amount The amount of ETH to transfer.
function _transferEth(address payable recipient, uint256 amount)
internal
{
if (amount > 0) {
(bool success,) = recipient.call{value: amount}("");
require(success, "FixinTokenSpender::_transferEth/TRANSFER_FAILED");
}
}
/// @dev Gets the maximum amount of an ERC20 token `token` that can be
/// pulled from `owner` by this address.
/// @param token The token to spend.

View File

@@ -0,0 +1,55 @@
// 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;
pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for `ERC1155OrdersFeature`.
library LibERC1155OrdersStorage {
struct OrderState {
// The amount (denominated in the ERC1155 asset)
// that the order has been filled by.
uint128 filledAmount;
// Whether the order has been pre-signed.
bool preSigned;
}
/// @dev Storage bucket for this feature.
struct Storage {
// Mapping from order hash to order state:
mapping(bytes32 => OrderState) orderState;
// maker => nonce range => order cancellation bit vector
mapping(address => mapping(uint248 => uint256)) orderCancellationByMaker;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.getStorageSlot(
LibStorage.StorageId.ERC1155Orders
);
// Dip into assembly to change the slot pointed to by the local
// variable `stor`.
// See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries
assembly { stor_slot := storageSlot }
}
}

View File

@@ -0,0 +1,47 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for `ERC721OrdersFeature`.
library LibERC721OrdersStorage {
/// @dev Storage bucket for this feature.
struct Storage {
// maker => nonce range => order status bit vector
mapping(address => mapping(uint248 => uint256)) orderStatusByMaker;
// order hash => isSigned
mapping(bytes32 => bool) preSigned;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.getStorageSlot(
LibStorage.StorageId.ERC721Orders
);
// Dip into assembly to change the slot pointed to by the local
// variable `stor`.
// See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries
assembly { stor_slot := storageSlot }
}
}

View File

@@ -17,7 +17,7 @@
*/
pragma solidity ^0.6.5;
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
@@ -39,7 +39,9 @@ library LibStorage {
MetaTransactions,
ReentrancyGuard,
NativeOrders,
OtcOrders
OtcOrders,
ERC721Orders,
ERC1155Orders
}
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced

View File

@@ -22,10 +22,13 @@ pragma experimental ABIEncoderV2;
import "./IBridgeAdapter.sol";
import "./BridgeProtocols.sol";
import "./mixins/MixinAaveV2.sol";
import "./mixins/MixinBalancer.sol";
import "./mixins/MixinBalancerV2.sol";
import "./mixins/MixinBalancerV2Batch.sol";
import "./mixins/MixinBancor.sol";
import "./mixins/MixinCoFiX.sol";
import "./mixins/MixinCompound.sol";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinCurveV2.sol";
import "./mixins/MixinCryptoCom.sol";
@@ -47,10 +50,13 @@ import "./mixins/MixinZeroExBridge.sol";
contract BridgeAdapter is
IBridgeAdapter,
MixinAaveV2,
MixinBalancer,
MixinBalancerV2,
MixinBalancerV2Batch,
MixinBancor,
MixinCoFiX,
MixinCompound,
MixinCurve,
MixinCurveV2,
MixinCryptoCom,
@@ -72,10 +78,12 @@ contract BridgeAdapter is
{
constructor(IEtherTokenV06 weth)
public
MixinAaveV2()
MixinBalancer()
MixinBalancerV2()
MixinBancor(weth)
MixinCoFiX()
MixinCompound(weth)
MixinCurve(weth)
MixinCurveV2()
MixinCryptoCom()
@@ -153,6 +161,11 @@ contract BridgeAdapter is
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.BALANCERV2BATCH) {
boughtAmount = _tradeBalancerV2Batch(
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.KYBER) {
boughtAmount = _tradeKyber(
sellToken,
@@ -245,6 +258,20 @@ contract BridgeAdapter is
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.AAVEV2) {
boughtAmount = _tradeAaveV2(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.COMPOUND) {
boughtAmount = _tradeCompound(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else {
boughtAmount = _tradeZeroExBridge(
sellToken,

View File

@@ -27,27 +27,30 @@ library BridgeProtocols {
// A incrementally increasing, append-only list of protocol IDs.
// We don't use an enum so solidity doesn't throw when we pass in a
// new protocol ID that hasn't been rolled up yet.
uint128 internal constant UNKNOWN = 0;
uint128 internal constant CURVE = 1;
uint128 internal constant UNISWAPV2 = 2;
uint128 internal constant UNISWAP = 3;
uint128 internal constant BALANCER = 4;
uint128 internal constant KYBER = 5;
uint128 internal constant MOONISWAP = 6;
uint128 internal constant MSTABLE = 7;
uint128 internal constant OASIS = 8;
uint128 internal constant SHELL = 9;
uint128 internal constant DODO = 10;
uint128 internal constant DODOV2 = 11;
uint128 internal constant CRYPTOCOM = 12;
uint128 internal constant BANCOR = 13;
uint128 internal constant COFIX = 14;
uint128 internal constant NERVE = 15;
uint128 internal constant MAKERPSM = 16;
uint128 internal constant BALANCERV2 = 17;
uint128 internal constant UNISWAPV3 = 18;
uint128 internal constant KYBERDMM = 19;
uint128 internal constant CURVEV2 = 20;
uint128 internal constant LIDO = 21;
uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface
uint128 internal constant UNKNOWN = 0;
uint128 internal constant CURVE = 1;
uint128 internal constant UNISWAPV2 = 2;
uint128 internal constant UNISWAP = 3;
uint128 internal constant BALANCER = 4;
uint128 internal constant KYBER = 5;
uint128 internal constant MOONISWAP = 6;
uint128 internal constant MSTABLE = 7;
uint128 internal constant OASIS = 8;
uint128 internal constant SHELL = 9;
uint128 internal constant DODO = 10;
uint128 internal constant DODOV2 = 11;
uint128 internal constant CRYPTOCOM = 12;
uint128 internal constant BANCOR = 13;
uint128 internal constant COFIX = 14;
uint128 internal constant NERVE = 15;
uint128 internal constant MAKERPSM = 16;
uint128 internal constant BALANCERV2 = 17;
uint128 internal constant UNISWAPV3 = 18;
uint128 internal constant KYBERDMM = 19;
uint128 internal constant CURVEV2 = 20;
uint128 internal constant LIDO = 21;
uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface
uint128 internal constant AAVEV2 = 23;
uint128 internal constant COMPOUND = 24;
uint128 internal constant BALANCERV2BATCH = 25;
}

View File

@@ -0,0 +1,93 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
// Minimal Aave V2 LendingPool interface
interface ILendingPool {
/**
* @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User deposits 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to deposit
* @param amount The amount to be deposited
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to Address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
**/
function withdraw(
address asset,
uint256 amount,
address to
) external returns (uint256);
}
contract MixinAaveV2 {
using LibERC20TokenV06 for IERC20TokenV06;
function _tradeAaveV2(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256)
{
(ILendingPool lendingPool, address aToken) = abi.decode(bridgeData, (ILendingPool, address));
sellToken.approveIfBelow(
address(lendingPool),
sellAmount
);
if (address(buyToken) == aToken) {
lendingPool.deposit(address(sellToken), sellAmount, address(this), 0);
// 1:1 mapping token -> aToken and have the same number of decimals as the underlying token
return sellAmount;
} else if (address(sellToken) == aToken) {
return lendingPool.withdraw(address(buyToken), sellAmount, address(this));
}
revert("MixinAaveV2/UNSUPPORTED_TOKEN_PAIR");
}
}

View File

@@ -0,0 +1,107 @@
// 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-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
interface IBalancerV2BatchSwapVault {
enum SwapKind { GIVEN_IN, GIVEN_OUT }
struct BatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
function batchSwap(
SwapKind kind,
BatchSwapStep[] calldata swaps,
IERC20TokenV06[] calldata assets,
FundManagement calldata funds,
int256[] calldata limits,
uint256 deadline
) external returns (int256[] memory amounts);
}
contract MixinBalancerV2Batch {
using LibERC20TokenV06 for IERC20TokenV06;
struct BalancerV2BatchBridgeData {
IBalancerV2BatchSwapVault vault;
IBalancerV2BatchSwapVault.BatchSwapStep[] swapSteps;
IERC20TokenV06[] assets;
}
function _tradeBalancerV2Batch(
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data.
(
IBalancerV2BatchSwapVault vault,
IBalancerV2BatchSwapVault.BatchSwapStep[] memory swapSteps,
address[] memory assets_
) = abi.decode(bridgeData, (IBalancerV2BatchSwapVault, IBalancerV2BatchSwapVault.BatchSwapStep[], address[]));
IERC20TokenV06[] memory assets;
assembly { assets := assets_ }
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
assets[0].approveIfBelow(address(vault), sellAmount);
swapSteps[0].amount = sellAmount;
int256[] memory limits = new int256[](assets.length);
for (uint256 i = 0; i < limits.length; ++i) {
limits[i] = type(int256).max;
}
int256[] memory amounts = vault.batchSwap(
IBalancerV2BatchSwapVault.SwapKind.GIVEN_IN,
swapSteps,
assets,
IBalancerV2BatchSwapVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(address(this)),
toInternalBalance: false
}),
limits,
block.timestamp + 1
);
require(amounts[amounts.length - 1] <= 0, 'Unexpected BalancerV2Batch output');
return uint256(amounts[amounts.length - 1] * -1);
}
}

View File

@@ -0,0 +1,110 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
/// @dev Minimal CToken interface
interface ICToken {
/// @dev deposits specified amount underlying tokens and mints cToken for the sender
/// @param mintAmountInUnderlying amount of underlying tokens to deposit to mint cTokens
/// @return status code of whether the mint was successful or not
function mint(uint256 mintAmountInUnderlying) external returns (uint256);
/// @dev redeems specified amount of cTokens and returns the underlying token to the sender
/// @param redeemTokensInCtokens amount of cTokens to redeem for underlying collateral
/// @return status code of whether the redemption was successful or not
function redeem(uint256 redeemTokensInCtokens) external returns (uint256);
}
/// @dev Minimal CEther interface
interface ICEther {
/// @dev deposits the amount of Ether sent as value and return mints cEther for the sender
function mint() payable external;
/// @dev redeems specified amount of cETH and returns the underlying ether to the sender
/// @dev redeemTokensInCEther amount of cETH to redeem for underlying ether
/// @return status code of whether the redemption was successful or not
function redeem(uint256 redeemTokensInCEther) external returns (uint256);
}
contract MixinCompound {
using LibERC20TokenV06 for IERC20TokenV06;
using LibSafeMathV06 for uint256;
IEtherTokenV06 private immutable WETH;
constructor(IEtherTokenV06 weth)
public
{
WETH = weth;
}
uint256 constant private COMPOUND_SUCCESS_CODE = 0;
function _tradeCompound(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256)
{
(address cTokenAddress) = abi.decode(bridgeData, (address));
uint256 beforeBalance = buyToken.balanceOf(address(this));
if (address(buyToken) == cTokenAddress) {
if (address(sellToken) == address(WETH)) {
// ETH/WETH -> cETH
ICEther cETH = ICEther(cTokenAddress);
// Compound expects ETH to be sent with mint call
WETH.withdraw(sellAmount);
// NOTE: cETH mint will revert on failure instead of returning a status code
cETH.mint{value: sellAmount}();
} else {
sellToken.approveIfBelow(
cTokenAddress,
sellAmount
);
// Token -> cToken
ICToken cToken = ICToken(cTokenAddress);
require(cToken.mint(sellAmount) == COMPOUND_SUCCESS_CODE, "MixinCompound/FAILED_TO_MINT_CTOKEN");
}
} else if (address(sellToken) == cTokenAddress) {
if (address(buyToken) == address(WETH)) {
// cETH -> ETH/WETH
uint256 etherBalanceBefore = address(this).balance;
ICEther cETH = ICEther(cTokenAddress);
require(cETH.redeem(sellAmount) == COMPOUND_SUCCESS_CODE, "MixinCompound/FAILED_TO_REDEEM_CETHER");
uint256 etherBalanceAfter = address(this).balance;
uint256 receivedEtherBalance = etherBalanceAfter.safeSub(etherBalanceBefore);
WETH.deposit{value: receivedEtherBalance}();
} else {
ICToken cToken = ICToken(cTokenAddress);
require(cToken.redeem(sellAmount) == COMPOUND_SUCCESS_CODE, "MixinCompound/FAILED_TO_REDEEM_CTOKEN");
}
}
return buyToken.balanceOf(address(this)).safeSub(beforeBalance);
}
}

View File

@@ -0,0 +1,151 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
interface IERC1155Token {
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
/// including zero value transfers as well as minting or burning.
/// Operator will always be msg.sender.
/// Either event from address `0x0` signifies a minting operation.
/// An event to address `0x0` signifies a burning or melting operation.
/// The total value transferred from address 0x0 minus the total value transferred to 0x0 may
/// be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
/// To define a token ID with no initial balance, the contract SHOULD emit the TransferSingle event
/// from `0x0` to `0x0`, with the token creator as `_operator`.
event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 value
);
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
/// including zero value transfers as well as minting or burning.
///Operator will always be msg.sender.
/// Either event from address `0x0` signifies a minting operation.
/// An event to address `0x0` signifies a burning or melting operation.
/// The total value transferred from address 0x0 minus the total value transferred to 0x0 may
/// be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
/// To define multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event
/// from `0x0` to `0x0`, with the token creator as `_operator`.
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/// @dev MUST emit when an approval is updated.
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
/// @dev MUST emit when the URI is updated for a token ID.
/// URIs are defined in RFC 3986.
/// The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata JSON Schema".
event URI(
string value,
uint256 indexed id
);
/// @notice Transfers value amount of an _id from the _from address to the _to address specified.
/// @dev MUST emit TransferSingle event on success.
/// Caller must be approved to manage the _from account's tokens (see isApprovedForAll).
/// MUST throw if `_to` is the zero address.
/// MUST throw if balance of sender for token `_id` is lower than the `_value` sent.
/// MUST throw on any other error.
/// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0).
/// If so, it MUST call `onERC1155Received` on `_to` and revert if the return value
/// is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`.
/// @param from Source address
/// @param to Target address
/// @param id ID of the token type
/// @param value Transfer amount
/// @param data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
)
external;
/// @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call).
/// @dev MUST emit TransferBatch event on success.
/// Caller must be approved to manage the _from account's tokens (see isApprovedForAll).
/// MUST throw if `_to` is the zero address.
/// MUST throw if length of `_ids` is not the same as length of `_values`.
/// MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_values` sent.
/// MUST throw on any other error.
/// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0).
/// If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return value
/// is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`.
/// @param from Source addresses
/// @param to Target addresses
/// @param ids IDs of each token type
/// @param values Transfer amounts per token type
/// @param data Additional data with no specified format, sent in call to `_to`
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external;
/// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens.
/// @dev MUST emit the ApprovalForAll event on success.
/// @param operator Address to add to the set of authorized operators
/// @param approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address operator, bool approved) external;
/// @notice Queries the approval status of an operator for a given owner.
/// @param owner The owner of the Tokens
/// @param operator Address of authorized operator
/// @return isApproved True if the operator is approved, false if not
function isApprovedForAll(address owner, address operator) external view returns (bool isApproved);
/// @notice Get the balance of an account's Tokens.
/// @param owner The address of the token holder
/// @param id ID of the Token
/// @return balance The _owner's balance of the Token type requested
function balanceOf(address owner, uint256 id) external view returns (uint256 balance);
/// @notice Get the balance of multiple account/token pairs
/// @param owners The addresses of the token holders
/// @param ids ID of the Tokens
/// @return balances_ The _owner's balance of the Token types requested
function balanceOfBatch(
address[] calldata owners,
uint256[] calldata ids
)
external
view
returns (uint256[] memory balances_);
}

View File

@@ -0,0 +1,159 @@
// 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;
interface IERC721Token {
/// @dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(
address indexed _from,
address indexed _to,
uint256 indexed _tokenId
);
/// @dev This emits when the approved address for an NFT is changed or
/// reaffirmed. The zero address indicates there is no approved address.
/// When a Transfer event emits, this also indicates that the approved
/// address for that NFT (if any) is reset to none.
event Approval(
address indexed _owner,
address indexed _approved,
uint256 indexed _tokenId
);
/// @dev This emits when an operator is enabled or disabled for an owner.
/// The operator can manage all NFTs of the owner.
event ApprovalForAll(
address indexed _owner,
address indexed _operator,
bool _approved
);
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// perator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT. When transfer is complete, this function
/// checks if `_to` is a smart contract (code size > 0). If so, it calls
/// `onERC721Received` on `_to` and throws if the return value is not
/// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
/// @param _data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes calldata _data
)
external;
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev This works identically to the other function with an extra data parameter,
/// except this function just sets data to "".
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
)
external;
/// @notice Change or reaffirm the approved address for an NFT
/// @dev The zero address indicates there is no approved address.
/// Throws unless `msg.sender` is the current NFT owner, or an authorized
/// operator of the current owner.
/// @param _approved The new approved NFT controller
/// @param _tokenId The NFT to approve
function approve(address _approved, uint256 _tokenId)
external;
/// @notice Enable or disable approval for a third party ("operator") to manage
/// all of `msg.sender`'s assets
/// @dev Emits the ApprovalForAll event. The contract MUST allow
/// multiple operators per owner.
/// @param _operator Address to add to the set of authorized operators
/// @param _approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address _operator, bool _approved)
external;
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by `_owner`, possibly zero
function balanceOf(address _owner)
external
view
returns (uint256);
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
external;
/// @notice Find the owner of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId)
external
view
returns (address);
/// @notice Get the approved address for a single NFT
/// @dev Throws if `_tokenId` is not a valid NFT.
/// @param _tokenId The NFT to find the approved address for
/// @return The approved address for this NFT, or the zero address if there is none
function getApproved(uint256 _tokenId)
external
view
returns (address);
/// @notice Query if an address is an authorized operator for another address
/// @param _owner The address that owns the NFTs
/// @param _operator The address that acts on behalf of the owner
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
function isApprovedForAll(address _owner, address _operator)
external
view
returns (bool);
}

View File

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
interface IFeeRecipient {
/// @dev A callback function invoked in the ERC721Feature for each ERC721
/// order fee that get paid. Integrators can make use of this callback
/// to implement arbitrary fee-handling logic, e.g. splitting the fee
/// between multiple parties.
/// @param tokenAddress The address of the token in which the received fee is
/// denominated. `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` indicates
/// that the fee was paid in the native token (e.g. ETH).
/// @param amount The amount of the given token received.
/// @param feeData Arbitrary data encoded in the `Fee` used by this callback.
/// @return success The selector of this function (0x0190805e),
/// indicating that the callback succeeded.
function receiveZeroExFeeCallback(
address tokenAddress,
uint256 amount,
bytes calldata feeData
)
external
returns (bytes4 success);
}

View File

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
interface IPropertyValidator {
/// @dev Checks that the given ERC721/ERC1155 asset satisfies the properties encoded in `propertyData`.
/// Should revert if the asset does not satisfy the specified properties.
/// @param tokenAddress The ERC721/ERC1155 token contract address.
/// @param tokenId The ERC721/ERC1155 tokenId of the asset to check.
/// @param propertyData Encoded properties or auxiliary data needed to perform the check.
function validateProperty(
address tokenAddress,
uint256 tokenId,
bytes calldata propertyData
)
external
view;
}

View File

@@ -0,0 +1,40 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
interface ITakerCallback {
/// @dev A taker callback function invoked in ERC721OrdersFeature and
/// ERC1155OrdersFeature between the maker -> taker transfer and
/// the taker -> maker transfer.
/// @param orderHash The hash of the order being filled when this
/// callback is invoked.
/// @param callbackData Arbitrary data used by this callback.
/// @return success The selector of this function,
/// indicating that the callback succeeded.
function zeroExTakerCallback(
bytes32 orderHash,
bytes calldata callbackData
)
external
returns (bytes4 success);
}

View File

@@ -0,0 +1,55 @@
// 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;
contract TestFeeRecipient {
bytes4 constant private SUCCESS = this.receiveZeroExFeeCallback.selector;
bytes4 constant private FAILURE = 0xdeadbeef;
uint256 constant private TRIGGER_REVERT = 333;
uint256 constant private TRIGGER_FAILURE = 666;
event FeeReceived(
address tokenAddress,
uint256 amount
);
receive() external payable {}
function receiveZeroExFeeCallback(
address tokenAddress,
uint256 amount,
bytes calldata /* feeData */
)
external
returns (bytes4 success)
{
emit FeeReceived(tokenAddress, amount);
if (amount == TRIGGER_REVERT) {
revert("TestFeeRecipient::receiveZeroExFeeCallback/REVERT");
} else if (amount == TRIGGER_FAILURE) {
return FAILURE;
} else {
return SUCCESS;
}
}
}

View File

@@ -22,7 +22,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../src/vendor/v3/IERC20Bridge.sol";
import "./TestMintableERC20Token.sol";
import "./tokens/TestMintableERC20Token.sol";
contract TestFillQuoteTransformerBridge {

View File

@@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "./TestMintableERC20Token.sol";
import "./tokens/TestMintableERC20Token.sol";
import "../src/features/libs/LibNativeOrder.sol";
import "../src/features/libs/LibSignature.sol";

View File

@@ -21,7 +21,7 @@ pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "../src/transformers/IERC20Transformer.sol";
import "./TestMintableERC20Token.sol";
import "./tokens/TestMintableERC20Token.sol";
import "./TestTransformerHost.sol";

View File

@@ -46,6 +46,10 @@ contract TestMetaTransactionsTransformERC20Feature is
payable
returns (uint256 outputTokenAmount)
{
if (msg.value == 555) {
tx.origin.transfer(1);
}
if (msg.value == 666) {
revert('FAIL');
}

View File

@@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../src/transformers/IERC20Transformer.sol";
import "../src/transformers/LibERC20Transformer.sol";
import "./TestMintableERC20Token.sol";
import "./tokens/TestMintableERC20Token.sol";
contract TestMintTokenERC20Transformer is

View File

@@ -0,0 +1,93 @@
// 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 "../src/IZeroEx.sol";
import "../src/vendor/IERC1155Token.sol";
import "../src/vendor/IERC721Token.sol";
import "../src/features/libs/LibNFTOrder.sol";
contract TestNFTOrderPresigner {
IZeroEx private immutable zeroEx;
constructor(IZeroEx _zeroEx)
public
{
zeroEx = _zeroEx;
}
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
)
external
returns(bytes4 success)
{
return 0xf23a6e61;
}
function approveERC721(IERC721Token token)
external
{
token.setApprovalForAll(address(zeroEx), true);
}
function approveERC1155(IERC1155Token token)
external
{
token.setApprovalForAll(address(zeroEx), true);
}
function approveERC20(IERC20TokenV06 token)
external
{
token.approve(address(zeroEx), uint256(-1));
}
function preSignERC721Order(LibNFTOrder.ERC721Order calldata order)
external
{
zeroEx.preSignERC721Order(order);
}
function preSignERC1155Order(LibNFTOrder.ERC1155Order calldata order)
external
{
zeroEx.preSignERC1155Order(order);
}
function cancelERC721Order(uint256 orderNonce)
external
{
zeroEx.cancelERC721Order(orderNonce);
}
function cancelERC1155Order(uint256 orderNonce)
external
{
zeroEx.cancelERC1155Order(orderNonce);
}
}

View File

@@ -0,0 +1,39 @@
// 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;
contract TestPropertyValidator {
function validateProperty(
address tokenAddress,
uint256 tokenId,
bytes calldata propertyData
)
external
view
{
require(
propertyData.length > 0,
"TestPropertyValidator::validateProperty/REVERT"
);
}
}

View File

@@ -21,9 +21,9 @@ pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "../src/transformers/IERC20Transformer.sol";
import "./TestMintableERC20Token.sol";
import "./tokens/TestMintableERC20Token.sol";
import "./TestTransformerHost.sol";
import "./TestWeth.sol";
import "./tokens/TestWeth.sol";
contract TestWethTransformerHost is

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 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;
import "forge-std/Test.sol";
contract ContractTest is Test {
function setUp() public {}
function testExample() public {
assertTrue(true);
}
}

View File

@@ -0,0 +1,66 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "src/features/OtcOrdersFeature.sol";
import "src/features/TransformERC20Feature.sol";
import "src/features/UniswapFeature.sol";
import "src/features/UniswapV3Feature.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../utils/DeployZeroEx.sol";
contract Architecture is DeployZeroEx {
function testFeatureDeployment()
public
{
deployZeroEx();
// If we look up the address of the Uniswap Implementation, it will be empty
// as it hasn't yet been registered.
emit log_named_address("sellToUniswap implementation", ZERO_EX.getFunctionImplementation(UniswapFeature.sellToUniswap.selector));
// Try registering the implementation
// Technically the constructor argument is the WETH address, which doesn't yet exist in this environment
UniswapFeature uniswapFeature = new UniswapFeature(IEtherTokenV06(address(0)));
emit log_named_address("UniswapFeature deployed at", address(uniswapFeature));
// As part of the migration, the UniswapFeature registers its own selectors
IZERO_EX.migrate(address(uniswapFeature), abi.encodePacked(uniswapFeature.migrate.selector), address(this));
// You will observe in the logs the following events
// ├─ emit ProxyFunctionUpdated(selector: 0xd9627aa4, oldImpl: 0x0000000000000000000000000000000000000000, newImpl: UniswapFeature: [0xf5a2fe45f4f1308502b1c136b9ef8af136141382])
// sellToUniswap(address[],uint256,uint256,bool) = 0xd9627aa4
// cast keccak 'sellToUniswap(address[],uint256,uint256,bool)'
// > 0xd9627aa4...
emit log_named_address("sellToUniswap implementation", ZERO_EX.getFunctionImplementation(UniswapFeature.sellToUniswap.selector));
// From now on it will be possible to call 0xEP.sellToUniswap which will be registered.
// Try deploying another Feature such as
// OtcOrdersFeature
// ...
emit log_named_address("fillOtcOrder implementation", ZERO_EX.getFunctionImplementation(OtcOrdersFeature.fillOtcOrder.selector));
// UniswapV3Feature
// ...
emit log_named_address("sellTokenForTokenToUniswapV3 implementation", ZERO_EX.getFunctionImplementation(UniswapV3Feature.sellTokenForTokenToUniswapV3.selector));
// Or for extra credit, the TransformERC20Feature
emit log_named_address("transformERC20 implementation", ZERO_EX.getFunctionImplementation(TransformERC20Feature.transformERC20.selector));
}
}

View File

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
interface LanguageContract {
function hello()
external
returns (address, string memory);
}
contract ContractA is LanguageContract {
function hello()
public
override
returns (address, string memory)
{
return (address(this), "Why hello there!");
}
}
contract ContractB is LanguageContract {
function hello()
public
override
returns (address, string memory)
{
return (address(this), "Protocol Academy was here");
}
}
contract DelegateCaller {
function delegateCall(address impl)
public
returns (address addr, string memory str)
{
(bool success, bytes memory resultData) = impl.delegatecall(abi.encodePacked(LanguageContract.hello.selector));
(addr, str) = abi.decode(resultData, (address, string));
}
}
contract DelegateCall is Test {
LanguageContract A;
LanguageContract B;
DelegateCaller caller;
function setUp()
public
{
A = new ContractA();
B = new ContractB();
caller = new DelegateCaller();
}
function testDelegateCall()
public
returns (uint256 val)
{
// ← DelegateCaller: [0xefc56627233b02ea95bae7e19f648d7dcd5bb132], "Why hello there!"
caller.delegateCall(address(A));
// ← DelegateCaller: [0xefc56627233b02ea95bae7e19f648d7dcd5bb132], "Protocol Academy was here"
caller.delegateCall(address(B));
// Note how in the above results the context is always the DelegateCaller context
// with address 0xefc56627233b02ea95bae7e19f648d7dcd5bb132
// ← ContractA: [0xce71065d4017f316ec606fe4422e11eb2c47c246], "Why hello there!"
A.hello();
// ← ContractB: [0x185a4dc360ce69bdccee33b3784b0282f7961aea], "Protocol Academy was here"
B.hello();
// Note how in the above results the context is each individual contract
}
}

View File

@@ -0,0 +1,75 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
import "src/IZeroEx.sol";
import "src/ZeroEx.sol";
import "src/migrations/InitialMigration.sol";
import "src/features/OtcOrdersFeature.sol";
import "src/features/OwnableFeature.sol";
import "src/features/SimpleFunctionRegistryFeature.sol";
import "src/features/TransformERC20Feature.sol";
import "src/features/UniswapFeature.sol";
import "src/features/UniswapV3Feature.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
contract StorageContract {
uint256 public storedValue = 0;
function increase()
public
returns (uint256)
{
storedValue++;
return storedValue;
}
}
contract OpcodeCosts is Test {
uint256 public storedValue = 0;
StorageContract store;
function setUp()
public
{
store = new StorageContract();
}
function testLoadFromStorage()
public
returns (uint256 val)
{
// [2306] StorageContract::storedValue() [staticcall]
val = store.storedValue();
}
function testLoadAndStore()
public
returns (uint256 val)
{
// [22346] StorageContract::increase()
val = store.increase();
}
}

View File

@@ -0,0 +1,93 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
import "src/IZeroEx.sol";
import "src/ZeroEx.sol";
import "src/features/interfaces/IFeature.sol";
import "src/features/TransformERC20Feature.sol";
import "../utils/TestUtils.sol";
// TODO: Try running this test on various networks
// forge test --match-contract DeployedFeatures --fork-url <rpc_url> -vvv
contract DeployedFeatures is TestUtils {
ZeroEx public ZERO_EX = ZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF);
IZeroEx public IZERO_EX = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF);
function testLookupFunction()
public
{
uint256 chainId;
assembly { chainId := chainid() }
// Skip if not in forking mode
if (chainId == 31337) {
emit log_string("Not in forking mode; skipping test");
return;
}
// TODO: try swapping out this selector
bytes4 selector = TransformERC20Feature.transformERC20.selector;
address impl = ZERO_EX.getFunctionImplementation(selector);
if (impl == address(0)) {
emit log_named_address("v0.0.0", impl);
} else {
uint256 version = IFeature(impl).FEATURE_VERSION();
// NOTE: we used to have a bug where the version was
// being incorrectly encoded as 0 lol
emit log_named_address(_versionString(version), impl);
}
uint256 rollbackLength = IZERO_EX.getRollbackLength(selector);
if (rollbackLength > 1) {
for (uint256 i = rollbackLength - 1; i > 0; i--) {
address prevImpl = IZERO_EX.getRollbackEntryAtIndex(selector, i);
if (prevImpl == address(0)) {
emit log_named_address("v0.0.0", prevImpl);
} else {
uint256 version = IFeature(prevImpl).FEATURE_VERSION();
emit log_named_address(_versionString(version), prevImpl);
}
}
}
}
function _versionString(uint256 encodedVersion)
private
pure
returns (string memory versionString)
{
uint32 major = uint32(encodedVersion >> 64);
uint32 minor = uint32(encodedVersion >> 32);
uint32 revision = uint32(encodedVersion);
return string(abi.encodePacked(
"v",
_toString(uint256(major)),
".",
_toString(uint256(minor)),
".",
_toString(uint256(revision))
));
}
}

View File

@@ -0,0 +1,132 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "src/fixins/FixinCommon.sol";
import "src/migrations/LibMigrate.sol";
import "../utils/DeployZeroEx.sol";
contract FibonacciFeature is FixinCommon {
uint256 private prevFib;
uint256 private fib;
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.stepFibonacci.selector);
_registerFeatureFunction(this.currentFibonacci.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
function stepFibonacci() external {
if (prevFib == 0 && fib == 0) {
fib = 1;
return;
} else {
uint256 nextFib = prevFib + fib;
prevFib = fib;
fib = nextFib;
}
}
function currentFibonacci() external view returns (uint256) {
return fib;
}
}
contract VoteFeature is FixinCommon {
uint256 private good;
uint256 private bad;
mapping (address => bool) hasVoted;
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.pineappleOnPizzaIsGood.selector);
_registerFeatureFunction(this.pineappleOnPizzaIsBad.selector);
_registerFeatureFunction(this.currentVotes.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
function pineappleOnPizzaIsGood() external {
require(!hasVoted[msg.sender]);
hasVoted[msg.sender] = true;
good++;
}
function pineappleOnPizzaIsBad() external {
require(!hasVoted[msg.sender]);
hasVoted[msg.sender] = true;
bad++;
}
function currentVotes() external view returns (uint256, uint256) {
return (good, bad);
}
}
contract FeatureStorage is DeployZeroEx {
function setUp() public {
deployZeroEx();
FibonacciFeature fibonacciFeature = new FibonacciFeature();
emit log_named_address("FibonacciFeature deployed at", address(fibonacciFeature));
IZERO_EX.migrate(address(fibonacciFeature), abi.encodePacked(fibonacciFeature.migrate.selector), address(this));
emit log_named_address("stepFibonacci implementation", ZERO_EX.getFunctionImplementation(FibonacciFeature.stepFibonacci.selector));
VoteFeature voteFeature = new VoteFeature();
emit log_named_address("VoteFeature deployed at", address(voteFeature));
IZERO_EX.migrate(address(voteFeature), abi.encodePacked(voteFeature.migrate.selector), address(this));
}
function testFeatureStorage()
public
{
for (uint256 i = 0; i < 10; i++) {
emit log_named_uint("fib", FibonacciFeature(address(ZERO_EX)).currentFibonacci());
FibonacciFeature(address(ZERO_EX)).stepFibonacci();
}
for (uint256 i = 0; i < 10; i++) {
address voter = _pseudoRandomAddress(i);
bool likesPineappleOnPizza = (uint160(voter) % 2) == 1;
hoax(voter);
likesPineappleOnPizza
? VoteFeature(address(ZERO_EX)).pineappleOnPizzaIsGood()
: VoteFeature(address(ZERO_EX)).pineappleOnPizzaIsBad();
}
(uint256 good, uint256 bad) = VoteFeature(address(ZERO_EX)).currentVotes();
emit log_named_uint("good votes", good);
emit log_named_uint("bad votes", bad);
emit log_named_uint("fib", FibonacciFeature(address(ZERO_EX)).currentFibonacci());
// TODO: Fix the Fibonacci and Vote features so that their respective storage
// variables do not collide. Create LibFibonacciStorage and LibVoteStorage
// to do so.
}
function _pseudoRandomAddress(uint256 seed) private pure returns (address) {
return address(uint160(uint256(keccak256(abi.encodePacked(seed)))));
}
}

View File

@@ -0,0 +1,155 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "src/fixins/FixinCommon.sol";
import "src/migrations/LibMigrate.sol";
import "../utils/DeployZeroEx.sol";
contract ZooFeature is FixinCommon {
event Meow();
event Woof();
event SlothNoises();
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.cat.selector);
_registerFeatureFunction(this.dog.selector);
_registerFeatureFunction(this.sloth.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
function cat() external {
emit Meow();
}
function dog() external {
emit Woof();
}
function sloth() external {
emit SlothNoises();
}
}
contract ZooFeatureV2 is FixinCommon {
event Meow();
event Purr();
event Woof();
event CapybaraNoises();
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.cat.selector);
_registerFeatureFunction(this.dog.selector);
_registerFeatureFunction(this.capybara.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
// NOTE: the function signature for `cat` has changed, so the selectors are different!
function cat(bool happy) external {
if (happy) {
emit Purr();
} else {
emit Meow();
}
}
// dog is the same
function dog() external {
emit Woof();
}
// new!
function capybara() external {
emit CapybaraNoises();
}
// sloth is not in V2
}
contract Migration is DeployZeroEx {
function setUp() public {
deployZeroEx();
}
function testMigration()
public
{
ZooFeature zooFeature = new ZooFeature();
IZERO_EX.migrate(address(zooFeature), abi.encodePacked(zooFeature.migrate.selector), address(this));
// The functions in ZooFeature are now registered in the exchange proxy!
// Try them out.
ZooFeature(address(ZERO_EX)).dog();
ZooFeature(address(ZERO_EX)).cat();
ZooFeature(address(ZERO_EX)).sloth();
}
function testUpgrade()
public
{
// Original version
ZooFeature zooFeature = new ZooFeature();
IZERO_EX.migrate(address(zooFeature), abi.encodePacked(zooFeature.migrate.selector), address(this));
// Upgrade
ZooFeatureV2 zooFeatureV2 = new ZooFeatureV2();
IZERO_EX.migrate(address(zooFeatureV2), abi.encodePacked(zooFeatureV2.migrate.selector), address(this));
// The functions in ZooFeatureV2 are now registered in the exchange proxy!
// Try them out.
ZooFeatureV2(address(ZERO_EX)).dog();
ZooFeatureV2(address(ZERO_EX)).cat(true);
ZooFeatureV2(address(ZERO_EX)).cat(false);
ZooFeatureV2(address(ZERO_EX)).capybara();
// `sloth` is still registered
ZooFeature(address(ZERO_EX)).sloth();
// The old `cat` function is still registered, since it has a different selector
emit log_named_bytes('cat()', abi.encodePacked(zooFeature.cat.selector));
emit log_named_bytes('cat(bool)', abi.encodePacked(zooFeatureV2.cat.selector));
ZooFeature(address(ZERO_EX)).cat();
// Let's deregister the sloth and old cat functions
IZERO_EX.rollback(zooFeature.cat.selector, address(0));
IZERO_EX.rollback(zooFeature.sloth.selector, address(0));
// Now trying to call the old cat or sloth reverts
try ZooFeature(address(ZERO_EX)).cat() {}
catch (bytes memory e) {
emit log_string("cat() reverted");
}
try ZooFeature(address(ZERO_EX)).sloth() {}
catch (bytes memory e) {
emit log_string("sloth() reverted");
}
// dog() was upgraded, so it's v1 address is in the `implHistory`
emit log_named_uint(
"dog() rollback length",
IZERO_EX.getRollbackLength(zooFeature.dog.selector)
);
emit log_named_address(
"dog() v1 is in the history",
IZERO_EX.getRollbackEntryAtIndex(zooFeature.dog.selector, 1)
);
}
}

View File

@@ -0,0 +1,152 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "../utils/ForkUtils.sol";
import "../utils/TestUtils.sol";
import "src/IZeroEx.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "src/features/TransformERC20Feature.sol";
import "src/external/TransformerDeployer.sol";
import "src/transformers/WethTransformer.sol";
import "src/transformers/FillQuoteTransformer.sol";
import "src/transformers/bridges/BridgeProtocols.sol";
import "src/transformers/bridges/BridgeAdapter.sol";
/*
This test must be run in forked mode
e.g forge test -vvvv -m 'testBasicSwap' -f ETH_RPC_URL
It is also helpful to have an Etherscan API key exported
export ETHERSCAN_API_KEY=
as Foundry will fetch source code and names
*/
contract BasicSwapForkedTest is
ForkUtils,
TestUtils
{
IZeroEx public IZERO_EX = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF);
IEtherTokenV06 WETH = IEtherTokenV06(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
// These addresses are taken from contract-addresses for Ethereum Mainnet
TransformerDeployer transformerDeployer = TransformerDeployer(0x39dCe47a67aD34344EAB877eaE3Ef1FA2a1d50Bb);
WethTransformer wethTransformer = WethTransformer(0xb2bc06a4EfB20FC6553a69Dbfa49B7bE938034A7);
// Note this may be outdated as it is often updated
FillQuoteTransformer fillQuoteTransformer = FillQuoteTransformer(0xADBE39F2988A8Be1C1120F05e28CC888b150c8a6);
function setUp()
public
onlyForked()
{
// HACK we deploy some fake transformers just so Foundry
// can detect these contracts for decoding
new WethTransformer(IEtherTokenV06(address(0)));
vm.label(address(wethTransformer), "WethTransformer");
new FillQuoteTransformer(IBridgeAdapter(address(0)), INativeOrdersFeature(address(0)));
vm.label(address(fillQuoteTransformer), "FillQuoteTransformer");
new BridgeAdapter(IEtherTokenV06(address(0)));
vm.label(address(fillQuoteTransformer.bridgeAdapter()), "BridgeAdapter");
vm.label(address(IZERO_EX.getTransformWallet()), "FlashWallet");
}
function testBasicSwap()
public
onlyForked()
{
IERC20TokenV06 USDC = IERC20TokenV06(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
// Create our list of transformations, let's do WethTransformer and FillQuoteTransformer
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](2);
// Use our cheeky search helper to find the nonce rather than hardcode it
// hint: it's 6 for WethTransformer and 22 for this FillQuoteTransformer
transformations[0].deploymentNonce = _findTransformerNonce(address(wethTransformer), address(transformerDeployer));
transformations[1].deploymentNonce = _findTransformerNonce(address(fillQuoteTransformer), address(transformerDeployer));
emit log_named_uint("WethTransformer nonce", transformations[0].deploymentNonce);
emit log_named_uint("FillQuoteTransformer nonce", transformations[1].deploymentNonce);
// Set the first transformation to transform ETH into WETH
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e18);
// Set up the FillQuoteTransformer data
FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell;
// FQT deals with tokens, not ETH, so it needs a WETH transformer
// to be applied beforehand
fqtData.sellToken = IERC20TokenV06(address(WETH));
fqtData.buyToken = IERC20TokenV06(address(USDC));
// the FQT has a sequence, e.g first RFQ then Limit then Bridge
// since solidity doesn't support arrays of different types, this is one simple solution
// We use a Bridge order type here as we will fill on UniswapV2
fqtData.fillSequence = new FillQuoteTransformer.OrderType[](1);
fqtData.fillSequence[0] = FillQuoteTransformer.OrderType.Bridge;
// The amount to fill
fqtData.fillAmount = 1e18;
// Now let's set up a UniswapV2 fill
fqtData.bridgeOrders = new IBridgeAdapter.BridgeOrder[](1);
IBridgeAdapter.BridgeOrder memory order;
// The ID is shifted so we can concat <PROTOCOL><NAME>
// e.g <UniswapV2Protocol><UniswapV2>
// or <UniswapV2Protocol><SushiSwap> for forks
order.source = bytes32(uint256(BridgeProtocols.UNISWAPV2) << 128);
// How much we want to fill on this order, which can be different to the total
// e.g 50/50 split this would be half
order.takerTokenAmount = 1e18;
// Set this low as the price of ETH/USDC can change
order.makerTokenAmount = 1;
// The data needed specifically for the source to fill,
// e.g for UniswapV2 it is the router contract and a path. See MixinUniswapV2
address[] memory uniPath = new address[](2);
uniPath[0] = address(WETH);
uniPath[1] = address(USDC);
order.bridgeData = abi.encode(address(0xf164fC0Ec4E93095b804a4795bBe1e041497b92a), uniPath);
fqtData.bridgeOrders[0] = order;
// Now encode the FQT data into the transformation
transformations[1].data = abi.encode(fqtData);
// Now let's do it!
// Give ourselves 1e18 ETH
vm.deal(address(this), 1e18);
IZERO_EX.transformERC20{value: 1e18}(
// input token
IERC20TokenV06(LibERC20Transformer.ETH_TOKEN_ADDRESS),
// output token
IERC20TokenV06(address(USDC)),
// input token amount
1e18,
// min output token amount, set this low as ETH/USDC price will move
1,
// list of transform
transformations
);
// Hoollly heck we bought some USDC
assertGt(USDC.balanceOf(address(this)), 0);
emit log_named_uint("USDC bought", USDC.balanceOf(address(this)));
/*
Homework
Try the following:
* make this UniswapV2 trade go ETH->DAI->USDC
* combine multiple trades, e.g Uniswap V2 ETH->USDC and ETH->DAI->USDC
* create a UniswapV3 trade
*/
}
}

View File

@@ -0,0 +1,191 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "../utils/DeployZeroEx.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "src/features/TransformERC20Feature.sol";
import "src/external/TransformerDeployer.sol";
import "src/transformers/WethTransformer.sol";
import "src/transformers/FillQuoteTransformer.sol";
import "@0x/contracts-erc20/contracts/src/v06/WETH9.sol";
contract TransformERC20FeatureTest is DeployZeroEx {
IEtherTokenV06 WETH;
TransformerDeployer transformerDeployer;
WethTransformer wethTransformer;
TransformERC20Feature transformERC20Feature;
function setUp() public {
deployZeroEx();
// Deploy from bytecode as this is Solidity v5
WETH = IEtherTokenV06(deployCode("foundry-artifacts/WETH9.sol/WETH9.json"));
emit log_named_address("WETH deployed at", address(WETH));
}
function testMigration()
public
{
// Note there is a lot here, so feel free to comment out further sections
// so you can read the logs and traces
/*
Deploy TransformERC20Feature
*/
// Create a new TransformerDeployer, which will deploy all future transformers
// Owners are typically EOA which are allowed to deploy
// For this we will use this current contract address
address[] memory owners = new address[](1);
owners[0] = address(this);
transformerDeployer = new TransformerDeployer(owners);
emit log_named_address("TransformerDeployer deployed at", address(transformerDeployer));
transformERC20Feature = new TransformERC20Feature();
emit log_named_address("TransformERC20Feature deployed at", address(transformERC20Feature));
// Migrate 0x EP and initialize the TransformERC20Feature
// Remember this performs a delegatecall and registers function selectors
// function migrate(address target, bytes calldata data, address newOwner)
IZERO_EX.migrate(
address(transformERC20Feature),
// Use encodeWithSelector to generate low level call data with the required arguments
// <function selector><arg1>
// The required migration function to call is the following:
// function migrate(address transformerDeployer)
// e.g ce5494bb00000000000000000000000042997ac9251e5bb0a61f4ff790e5b991ea07fd9b
// try: cast calldata 'migrate(address)' '0x42997ac9251e5bb0a61f4ff790e5b991ea07fd9b'
abi.encodeWithSelector(transformERC20Feature.migrate.selector, address(transformerDeployer)),
address(this)
);
// As part of the migration process a FlashWallet was generated inside of the 0x EP context
emit log_named_address("FlashWallet deployed at", address(IZERO_EX.getTransformWallet()));
// Homework: Recall why transformERC20Feature.getTransformWallet() returns address(0)
/*
Deploy a WETH transformer
*/
// Typically the code to deployed is passed in off-chain, so we will emulate something similar
// by using vm.getCode cheatcode.
wethTransformer = WethTransformer(transformerDeployer.deploy(
abi.encodePacked(
// Deploy the WethTransformer code
vm.getCode("foundry-artifacts/WethTransformer.sol/WethTransformer.json"),
// WethTransformer takes WETH address as a constructor argument
abi.encode(address(WETH))
)
));
assertEq(address(wethTransformer.weth()), address(WETH));
emit log_named_address("WethTransformer deployed at", address(IZERO_EX.getTransformWallet()));
// Not much we can do with just a WethTransformer, I guess we could go ETH->WETH with it
// Cheat code to give this contract 1e18 ETH
vm.deal(address(this), 1e18);
// Deployment nonce is 1 as it is the first contract TransformerDeployer deployed
// let's assert that is true
assertEq(
LibERC20Transformer.getDeployedAddress(address(transformerDeployer), 1),
address(wethTransformer)
);
/*
Perform a ETH->WETH transformation
*/
// Create our list of transformations, this will just have a WethTransformer
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
transformations[0].deploymentNonce = 1;
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e18);
IZERO_EX.transformERC20{value: 1e18}(
// input token
IERC20TokenV06(LibERC20Transformer.ETH_TOKEN_ADDRESS),
// output token
IERC20TokenV06(address(WETH)),
// input token amount
1e18,
// min output token amount
1e18,
// list of transform
transformations
);
assertEq(WETH.balanceOf(address(this)), 1e18);
/*
Perform a WETH->ETH transformation
*/
// Let's go backwards, remember we need to set the approval of WETH to the 0x EP
WETH.approve(address(IZERO_EX), uint256(-1));
// Override the data in the previous transformation
transformations[0].data = abi.encode(address(WETH), 1e18);
// Note: No { value } here as it's a token
IZERO_EX.transformERC20(
// input token
IERC20TokenV06(address(WETH)),
// output token
IERC20TokenV06(LibERC20Transformer.ETH_TOKEN_ADDRESS),
// input token amount
1e18,
// min output token amount
1e18,
// list of transform
transformations
);
/*
Deploy FillQuoteTransformer and BridgeAdapter
*/
// At this time I would show how to do a ETH->USDC trade
// but we need to set up more of the world, or to run in forked mode
// with an AMM (find this in BasicSwapForked.t.sol)
// Instead let's just deploy the FQT and BridgeAdapter and as homework
// you might explore running in forked mode and using transformations
address bridgeAdapter = deployCode("foundry-artifacts/BridgeAdapter.sol/BridgeAdapter.json", abi.encode(address(WETH)));
FillQuoteTransformer fillQuoteTransformer = FillQuoteTransformer(transformerDeployer.deploy(
abi.encodePacked(
// Deploy the FillQuoteTransformer code
vm.getCode("foundry-artifacts/FillQuoteTransformer.sol/FillQuoteTransformer.json"),
// FillQuoteTransformer takes the BridgeAdapter and ZeroEx address as arguments
abi.encode(bridgeAdapter, address(ZERO_EX))
)
));
assertEq(address(fillQuoteTransformer.bridgeAdapter()), bridgeAdapter);
assertEq(
LibERC20Transformer.getDeployedAddress(address(transformerDeployer), 2),
address(fillQuoteTransformer)
);
}
// Note this is needed as the test is a contract, and to receive ETH
// it needs to declare a receive function as per the Solidity requirements
receive() external payable {}
}

View File

@@ -0,0 +1,88 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
contract Receiver {
function receivePure() public pure {
1 + 1;
}
function receiveImpure() public {
1 + 1;
}
}
contract Empty {
}
contract Call {
address empty = address(new Empty());
address receiver = address(new Receiver());
function callUnknown() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Call.t.sol --sig 'callUnknown()' --tc Call
// Why didn't this contract make a call out to 0x222... ?
// Did solidity add a check for us?
Receiver(0x2222222222222222222222222222222222222222).receiveImpure();
}
function callEmpty() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Call.t.sol --sig 'callEmpty()' --tc Call
// Observe how the added Solidity checks "pass"
// and ultimately how this results in a REVERT
Receiver(empty).receiveImpure();
}
function callEmptyRaw() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Call.t.sol --sig 'callEmptyRaw()' --tc Call
// Observe this low level call and how it differs from the above
// example. Does it revert?
empty.call(abi.encodeWithSelector(Receiver.receiveImpure.selector));
}
function callEmptyEOA() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Call.t.sol --sig 'callEmptyEOA()' --tc Call
// Observe this low level call and how it differs from the above
// example. Does it revert?
address(msg.sender).call(abi.encodeWithSelector(Receiver.receiveImpure.selector));
}
function callReceiverImpure() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Call.t.sol --sig 'callReceiverImpure()' --tc Call
// Observe how a CALL is set up and then ultimately made
// and any checks prior to making the CALL
Receiver(receiver).receiveImpure();
}
function callReceiverPure() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Call.t.sol --sig 'callReceiverPure()' --tc Call
// Did you notice the different CALL type solidity chose here ?
Receiver(receiver).receivePure();
}
}

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
contract Counter {
uint256 private data = 1337;
function increment(uint256 val) public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Counter.t.sol --sig 'increment(uint256)' 10
data += val;
}
}

View File

@@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
contract Hash {
bytes data = hex"42";
function sha3() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Hash.sol --sig 'sha3()'
// Follow the opcodes:
// how does the data get loaded
// which one is keccak256
keccak256(data);
}
function sha2() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Hash.sol --sig 'sha2()'
// Follow the opcodes:
// why is sha256 so different from keccak256
sha256(data);
}
}

View File

@@ -0,0 +1,45 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
contract Memory {
function expand() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Memory.t.sol --sig 'expand()'
// Observe the free memory pointer increase
// when more memory is allocated
bytes32[3] memory data;
}
function mstore() public {
// forge debug contracts/test/foundry/protocol-academy/8-evm/Memory.t.sol --sig 'mstore()'
// Observe the free memory pointer increase
// when more memory is allocated
bytes1[4] memory data;
// Observe each value being set in the memory
// slots
data[1] = 0x42;
data[0] = 0x0a;
data[2] = 0xff;
}
}

View File

@@ -0,0 +1,70 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
import "src/IZeroEx.sol";
import "src/ZeroEx.sol";
import "src/migrations/InitialMigration.sol";
import "src/features/OwnableFeature.sol";
import "src/features/SimpleFunctionRegistryFeature.sol";
contract DeployZeroEx is Test {
ZeroEx public ZERO_EX = ZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF);
IZeroEx public IZERO_EX = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF);
function deployZeroEx()
internal
{
// HERE BE DRAGONS, feel free to ignore this for now
// We want to deploy the ZeroEx contract, at 0xDef1C0ded9bec7F1a1670819833240f027b25EfF
// We use a special mechanism to deploy the ZeroEx contract.
InitialMigration initialMigration = InitialMigration(deployCode(
"foundry-artifacts/InitialMigration.sol/InitialMigration.json",
abi.encode(address(this))
));
// Must occur from this address as the first transaction
hoax(0xe750ad66DE350F8110E305fb78Ec6A9f594445E3);
// Special Deployer code
bytes memory deployerBytecode = hex"608060405234801561001057600080fd5b506040516103da3803806103da83398101604081905261002f91610077565b8060405161003c9061006a565b610046919061011f565b604051809103906000f080158015610062573d6000803e3d6000fd5b505050610198565b6101f5806101e583390190565b600060208284031215610088578081fd5b81516001600160401b038082111561009e578283fd5b818401915084601f8301126100b1578283fd5b8151818111156100c3576100c3610182565b604051601f8201601f19908116603f011681019083821181831017156100eb576100eb610182565b81604052828152876020848701011115610103578586fd5b610114836020830160208801610152565b979650505050505050565b600060208252825180602084015261013e816040850160208701610152565b601f01601f19169190910160400192915050565b60005b8381101561016d578181015183820152602001610155565b8381111561017c576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b603f806101a66000396000f3fe6080604052600080fdfea26469706673582212201bd8b1a777b100d67435ca4bb0b2fdccb13a2c2dde019b227bb553ff9a95bd4464736f6c63430008020033608060405234801561001057600080fd5b506040516101f53803806101f583398101604081905261002f916100c9565b60008151602083016000f090506001600160a01b0381166100865760405162461bcd60e51b815260206004820152600d60248201526c1111541313d657d19052531151609a1b604482015260640160405180910390fd5b6040516001600160a01b03821681527ff40fcec21964ffb566044d083b4073f29f7f7929110ea19e1b3ebe375d89055e9060200160405180910390a150506101a8565b600060208083850312156100db578182fd5b82516001600160401b03808211156100f1578384fd5b818501915085601f830112610104578384fd5b81518181111561011657610116610192565b604051601f8201601f19908116603f0116810190838211818310171561013e5761013e610192565b816040528281528886848701011115610155578687fd5b8693505b828410156101765784840186015181850187015292850192610159565b8284111561018657868684830101525b98975050505050505050565b634e487b7160e01b600052604160045260246000fd5b603f806101b66000396000f3fe6080604052600080fdfea2646970667358221220fbca036a163ed7f008cefa7c834d98d25109a456a051d41d9c89d55d7185d12b64736f6c63430008020033";
// Grab the bytecode of the ZeroEx artifact
bytes memory zeroExBytecode = vm.getCode("foundry-artifacts/ZeroEx.sol/ZeroEx.json");
// Append the required ZeroEx constructor arguments (address bootstrapper)
bytes memory zeroExDeploycode = abi.encodePacked(zeroExBytecode, abi.encode(initialMigration));
// Append the required deployer code constructor arguments (bytes initCode)
bytes memory deployerDeploycode = abi.encodePacked(deployerBytecode, abi.encode(zeroExDeploycode));
// The address is technically emitted in an event, but we know we did it correctly
//│ │ ├─ emit topic 0: 0xf40fcec21964ffb566044d083b4073f29f7f7929110ea19e1b3ebe375d89055e
//│ │ │ data: 0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff
assembly {
pop(create(0, add(deployerDeploycode, 0x20), mload(deployerDeploycode)))
}
initialMigration.initializeZeroEx(
payable(address(this)),
ZERO_EX,
InitialMigration.BootstrapFeatures({ registry: new SimpleFunctionRegistryFeature(), ownable: new OwnableFeature()})
);
}
}

View File

@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
contract ForkUtils is Test {
/// Only run this function if the block number
// is greater than some constant for Ethereum Mainnet
modifier onlyForked {
if (block.number >= 14206900) {
_;
} else {
emit log_string("Requires fork mode, skipping");
}
}
}

View File

@@ -0,0 +1,79 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
import "src/transformers/LibERC20Transformer.sol";
contract TestUtils is Test {
uint256 private constant MAX_UINT256_STRING_LENGTH = 78;
uint8 private constant ASCII_DIGIT_OFFSET = 48;
function _toString(uint256 n)
internal
pure
returns (string memory nstr)
{
if (n == 0) {
return "0";
}
// Overallocate memory
nstr = new string(MAX_UINT256_STRING_LENGTH);
uint256 k = MAX_UINT256_STRING_LENGTH;
// Populate string from right to left (lsb to msb).
while (n != 0) {
assembly {
let char := add(
ASCII_DIGIT_OFFSET,
mod(n, 10)
)
mstore(add(nstr, k), char)
k := sub(k, 1)
n := div(n, 10)
}
}
assembly {
// Shift pointer over to actual start of string.
nstr := add(nstr, k)
// Store actual string length.
mstore(nstr, sub(MAX_UINT256_STRING_LENGTH, k))
}
return nstr;
}
function _findTransformerNonce(
address transformer,
address deployer
)
internal
pure
returns (uint32)
{
address current;
for (uint32 i = 0; i < 1024; i++) {
current = LibERC20Transformer.getDeployedAddress(deployer, i);
if (current == transformer) {
return i;
}
}
}
}

View File

@@ -21,7 +21,7 @@ pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./TestMintableERC20Token.sol";
import "../tokens/TestMintableERC20Token.sol";
contract TestCurve {

View File

@@ -21,7 +21,7 @@ pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./TestMintableERC20Token.sol";
import "../tokens/TestMintableERC20Token.sol";
contract TestMooniswap {

View File

@@ -2,7 +2,7 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../src/vendor/IUniswapV2Pair.sol";
import "../../src/vendor/IUniswapV2Pair.sol";
interface IUniswapV2PoolDeployer {
struct CreationParameters {

View File

@@ -2,7 +2,7 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../src/vendor/IUniswapV3Pool.sol";
import "../../src/vendor/IUniswapV3Pool.sol";
interface IUniswapV3PoolDeployer {
struct CreationParameters {

View File

@@ -0,0 +1,345 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
interface IERC1155Receiver {
/// @notice Handle the receipt of a single ERC1155 token type
/// @dev The smart contract calls this function on the recipient
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
/// transfer. Return of other than the magic value MUST result in the
///transaction being reverted
/// Note: the contract address is always the message sender
/// @param operator The address which called `safeTransferFrom` function
/// @param from The address which previously owned the token
/// @param id An array containing the ids of the token being transferred
/// @param value An array containing the amount of tokens being transferred
/// @param data Additional data with no specified format
/// @return success `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
)
external
returns(bytes4 success);
/// @notice Handle the receipt of multiple ERC1155 token types
/// @dev The smart contract calls this function on the recipient
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
/// transfer. Return of other than the magic value MUST result in the
/// transaction being reverted
/// Note: the contract address is always the message sender
/// @param operator The address which called `safeTransferFrom` function
/// @param from The address which previously owned the token
/// @param ids An array containing ids of each token being transferred
/// @param values An array containing amounts of each token being transferred
/// @param data Additional data with no specified format
/// @return success `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external
returns(bytes4 success);
}
contract TestMintableERC1155Token {
using LibSafeMathV06 for uint256;
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
/// including zero value transfers as well as minting or burning.
/// Operator will always be msg.sender.
/// Either event from address `0x0` signifies a minting operation.
/// An event to address `0x0` signifies a burning or melting operation.
/// The total value transferred from address 0x0 minus the total value transferred to 0x0 may
/// be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
/// To define a token ID with no initial balance, the contract SHOULD emit the TransferSingle event
/// from `0x0` to `0x0`, with the token creator as `_operator`.
event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 value
);
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
/// including zero value transfers as well as minting or burning.
///Operator will always be msg.sender.
/// Either event from address `0x0` signifies a minting operation.
/// An event to address `0x0` signifies a burning or melting operation.
/// The total value transferred from address 0x0 minus the total value transferred to 0x0 may
/// be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
/// To define multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event
/// from `0x0` to `0x0`, with the token creator as `_operator`.
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/// @dev MUST emit when an approval is updated.
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
// selectors for receiver callbacks
bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61;
bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81;
// id => (owner => balance)
mapping (uint256 => mapping(address => uint256)) internal balances;
// owner => (operator => approved)
mapping (address => mapping(address => bool)) internal operatorApproval;
function mint(
address to,
uint256 id,
uint256 quantity
)
external
{
// Grant the items to the caller
balances[id][to] = quantity.safeAdd(balances[id][to]);
// Emit the Transfer/Mint event.
// the 0x0 source address implies a mint
// It will also provide the circulating supply info.
emit TransferSingle(
msg.sender,
address(0x0),
to,
id,
quantity
);
// if `to` is a contract then trigger its callback
uint256 receiverCodeSize;
assembly {
receiverCodeSize := extcodesize(to)
}
if (receiverCodeSize > 0) {
bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155Received(
msg.sender,
msg.sender,
id,
quantity,
""
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
/// @notice Transfers value amount of an _id from the _from address to the _to address specified.
/// @dev MUST emit TransferSingle event on success.
/// Caller must be approved to manage the _from account's tokens (see isApprovedForAll).
/// MUST throw if `_to` is the zero address.
/// MUST throw if balance of sender for token `_id` is lower than the `_value` sent.
/// MUST throw on any other error.
/// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0).
/// If so, it MUST call `onERC1155Received` on `_to` and revert if the return value
/// is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`.
/// @param from Source address
/// @param to Target address
/// @param id ID of the token type
/// @param value Transfer amount
/// @param data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
)
external
{
// sanity checks
require(
to != address(0x0),
"CANNOT_TRANSFER_TO_ADDRESS_ZERO"
);
require(
from == msg.sender || operatorApproval[from][msg.sender] == true,
"INSUFFICIENT_ALLOWANCE"
);
// perform transfer
balances[id][from] = balances[id][from].safeSub(value);
balances[id][to] = balances[id][to].safeAdd(value);
emit TransferSingle(msg.sender, from, to, id, value);
// if `to` is a contract then trigger its callback
uint256 receiverCodeSize;
assembly {
receiverCodeSize := extcodesize(to)
}
if (receiverCodeSize > 0) {
bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155Received(
msg.sender,
from,
id,
value,
data
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
/// @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call).
/// @dev MUST emit TransferBatch event on success.
/// Caller must be approved to manage the _from account's tokens (see isApprovedForAll).
/// MUST throw if `_to` is the zero address.
/// MUST throw if length of `_ids` is not the same as length of `_values`.
/// MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_values` sent.
/// MUST throw on any other error.
/// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0).
/// If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return value
/// is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`.
/// @param from Source addresses
/// @param to Target addresses
/// @param ids IDs of each token type
/// @param values Transfer amounts per token type
/// @param data Additional data with no specified format, sent in call to `_to`
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external
{
// sanity checks
require(
to != address(0x0),
"CANNOT_TRANSFER_TO_ADDRESS_ZERO"
);
require(
ids.length == values.length,
"TOKEN_AND_VALUES_LENGTH_MISMATCH"
);
// Only supporting a global operator approval allows us to do
// only 1 check and not to touch storage to handle allowances.
require(
from == msg.sender || operatorApproval[from][msg.sender] == true,
"INSUFFICIENT_ALLOWANCE"
);
// perform transfers
for (uint256 i = 0; i < ids.length; ++i) {
// Cache value to local variable to reduce read costs.
uint256 id = ids[i];
uint256 value = values[i];
balances[id][from] = balances[id][from].safeSub(value);
balances[id][to] = balances[id][to].safeAdd(value);
}
emit TransferBatch(msg.sender, from, to, ids, values);
// if `to` is a contract then trigger its callback
uint256 receiverCodeSize;
assembly {
receiverCodeSize := extcodesize(to)
}
if (receiverCodeSize > 0) {
bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155BatchReceived(
msg.sender,
from,
ids,
values,
data
);
require(
callbackReturnValue == ERC1155_BATCH_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
/// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens.
/// @dev MUST emit the ApprovalForAll event on success.
/// @param operator Address to add to the set of authorized operators
/// @param approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address operator, bool approved) external {
operatorApproval[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
/// @notice Queries the approval status of an operator for a given owner.
/// @param owner The owner of the Tokens
/// @param operator Address of authorized operator
/// @return isApproved True if the operator is approved, false if not
function isApprovedForAll(address owner, address operator) external view returns (bool isApproved) {
return operatorApproval[owner][operator];
}
/// @notice Get the balance of an account's Tokens.
/// @param owner The address of the token holder
/// @param id ID of the Token
/// @return balance The _owner's balance of the Token type requested
function balanceOf(address owner, uint256 id) external view returns (uint256 balance) {
return balances[id][owner];
}
/// @notice Get the balance of multiple account/token pairs
/// @param owners The addresses of the token holders
/// @param ids ID of the Tokens
/// @return balances_ The _owner's balance of the Token types requested
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view returns (uint256[] memory balances_) {
// sanity check
require(
owners.length == ids.length,
"OWNERS_AND_IDS_MUST_HAVE_SAME_LENGTH"
);
// get balances
balances_ = new uint256[](owners.length);
for (uint256 i = 0; i < owners.length; ++i) {
uint256 id = ids[i];
balances_[i] = balances[id][owners[i]];
}
return balances_;
}
}

View File

@@ -0,0 +1,385 @@
// 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/LibSafeMathV06.sol";
interface IERC721Receiver {
/// @notice Handle the receipt of an NFT
/// @dev The ERC721 smart contract calls this function on the recipient
/// after a `transfer`. This function MAY throw to revert and reject the
/// transfer. Return of other than the magic value MUST result in the
/// transaction being reverted.
/// Note: the contract address is always the message sender.
/// @param _operator The address which called `safeTransferFrom` function
/// @param _from The address which previously owned the token
/// @param _tokenId The NFT identifier which is being transferred
/// @param _data Additional data with no specified format
/// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
/// unless throwing
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes calldata _data
)
external
returns (bytes4);
}
contract TestMintableERC721Token {
using LibSafeMathV06 for uint256;
/// @dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(
address _from,
address _to,
uint256 _tokenId
);
/// @dev This emits when the approved address for an NFT is changed or
/// reaffirmed. The zero address indicates there is no approved address.
/// When a Transfer event emits, this also indicates that the approved
/// address for that NFT (if any) is reset to none.
event Approval(
address indexed _owner,
address indexed _approved,
uint256 indexed _tokenId
);
/// @dev This emits when an operator is enabled or disabled for an owner.
/// The operator can manage all NFTs of the owner.
event ApprovalForAll(
address indexed _owner,
address indexed _operator,
bool _approved
);
// Function selector for ERC721Receiver.onERC721Received
// 0x150b7a02
bytes4 constant private ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
// Mapping of tokenId => owner
mapping (uint256 => address) private owners;
// Mapping of tokenId => approved address
mapping (uint256 => address) private approvals;
// Mapping of owner => number of tokens owned
mapping (address => uint256) private balances;
// Mapping of owner => operator => approved
mapping (address => mapping (address => bool)) private operatorApprovals;
/// @dev Function to mint a new token
/// Reverts if the given token ID already exists
/// @param _to Address of the beneficiary that will own the minted token
/// @param _tokenId ID of the token to be minted by the msg.sender
function mint(address _to, uint256 _tokenId)
external
{
require(
_to != address(0),
"ERC721_ZERO_TO_ADDRESS"
);
address owner = owners[_tokenId];
require(
owner == address(0),
"ERC721_OWNER_ALREADY_EXISTS"
);
owners[_tokenId] = _to;
balances[_to] = balances[_to].safeAdd(1);
emit Transfer(
address(0),
_to,
_tokenId
);
}
/// @dev Function to burn a token
/// Reverts if the given token ID doesn't exist
/// @param _owner Owner of token with given token ID
/// @param _tokenId ID of the token to be burned by the msg.sender
function burn(address _owner, uint256 _tokenId)
external
{
require(
_owner != address(0),
"ERC721_ZERO_OWNER_ADDRESS"
);
address owner = owners[_tokenId];
require(
owner == _owner,
"ERC721_OWNER_MISMATCH"
);
owners[_tokenId] = address(0);
balances[_owner] = balances[_owner].safeSub(1);
emit Transfer(
_owner,
address(0),
_tokenId
);
}
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT. When transfer is complete, this function
/// checks if `_to` is a smart contract (code size > 0). If so, it calls
/// `onERC721Received` on `_to` and throws if the return value is not
/// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
/// @param _data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes calldata _data
)
external
{
transferFrom(
_from,
_to,
_tokenId
);
uint256 receiverCodeSize;
assembly {
receiverCodeSize := extcodesize(_to)
}
if (receiverCodeSize > 0) {
bytes4 selector = IERC721Receiver(_to).onERC721Received(
msg.sender,
_from,
_tokenId,
_data
);
require(
selector == ERC721_RECEIVED,
"ERC721_INVALID_SELECTOR"
);
}
}
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev This works identically to the other function with an extra data parameter,
/// except this function just sets data to "".
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
)
external
{
transferFrom(
_from,
_to,
_tokenId
);
uint256 receiverCodeSize;
assembly {
receiverCodeSize := extcodesize(_to)
}
if (receiverCodeSize > 0) {
bytes4 selector = IERC721Receiver(_to).onERC721Received(
msg.sender,
_from,
_tokenId,
""
);
require(
selector == ERC721_RECEIVED,
"ERC721_INVALID_SELECTOR"
);
}
}
/// @notice Change or reaffirm the approved address for an NFT
/// @dev The zero address indicates there is no approved address.
/// Throws unless `msg.sender` is the current NFT owner, or an authorized
/// operator of the current owner.
/// @param _approved The new approved NFT controller
/// @param _tokenId The NFT to approve
function approve(address _approved, uint256 _tokenId)
external
{
address owner = ownerOf(_tokenId);
require(
msg.sender == owner || isApprovedForAll(owner, msg.sender),
"ERC721_INVALID_SENDER"
);
approvals[_tokenId] = _approved;
emit Approval(
owner,
_approved,
_tokenId
);
}
/// @notice Enable or disable approval for a third party ("operator") to manage
/// all of `msg.sender`'s assets
/// @dev Emits the ApprovalForAll event. The contract MUST allow
/// multiple operators per owner.
/// @param _operator Address to add to the set of authorized operators
/// @param _approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address _operator, bool _approved)
external
{
operatorApprovals[msg.sender][_operator] = _approved;
emit ApprovalForAll(
msg.sender,
_operator,
_approved
);
}
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by `_owner`, possibly zero
function balanceOf(address _owner)
external
view
returns (uint256)
{
require(
_owner != address(0),
"ERC721_ZERO_OWNER"
);
return balances[_owner];
}
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
{
require(
_to != address(0),
"ERC721_ZERO_TO_ADDRESS"
);
address owner = ownerOf(_tokenId);
require(
_from == owner,
"ERC721_OWNER_MISMATCH"
);
address spender = msg.sender;
address approvedAddress = getApproved(_tokenId);
require(
spender == owner ||
isApprovedForAll(owner, spender) ||
approvedAddress == spender,
"ERC721_INVALID_SPENDER"
);
if (approvedAddress != address(0)) {
approvals[_tokenId] = address(0);
}
owners[_tokenId] = _to;
balances[_from] = balances[_from].safeSub(1);
balances[_to] = balances[_to].safeAdd(1);
emit Transfer(
_from,
_to,
_tokenId
);
}
/// @notice Find the owner of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId)
public
view
returns (address)
{
address owner = owners[_tokenId];
require(
owner != address(0),
"ERC721_ZERO_OWNER"
);
return owner;
}
/// @notice Get the approved address for a single NFT
/// @dev Throws if `_tokenId` is not a valid NFT.
/// @param _tokenId The NFT to find the approved address for
/// @return The approved address for this NFT, or the zero address if there is none
function getApproved(uint256 _tokenId)
public
view
returns (address)
{
return approvals[_tokenId];
}
/// @notice Query if an address is an authorized operator for another address
/// @param _owner The address that owns the NFTs
/// @param _operator The address that acts on behalf of the owner
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
function isApprovedForAll(address _owner, address _operator)
public
view
returns (bool)
{
return operatorApprovals[_owner][_operator];
}
}

View File

@@ -0,0 +1,8 @@
[default]
src = 'contracts/src'
out = 'foundry-artifacts'
test = 'contracts/test/foundry'
libs = ["../utils/contracts/src/", "contracts/deps/"]
remappings = ['@0x/contracts-utils/=../utils/', '@0x/contracts-erc20/=../erc20/', 'src/=./contracts/src']
cache_path = 'foundry-cache'
optimizer_runs = 1000000

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-zero-ex",
"version": "0.29.3",
"version": "0.32.0",
"engines": {
"node": ">=6.12"
},
@@ -38,12 +38,13 @@
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES",
"publish:private": "yarn build && gitpkg publish",
"rollback": "node ./lib/scripts/rollback.js"
"rollback": "node ./lib/scripts/rollback.js",
"typechain": "typechain --target=ethers-v5 --out-dir='typechain-wrappers' './foundry-artifacts/**/*.json'"
},
"config": {
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBalancerV2Batch|MixinBancor|MixinCoFiX|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
},
"repository": {
"type": "git",
@@ -55,16 +56,17 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
"devDependencies": {
"@0x/abi-gen": "^5.6.2",
"@0x/contract-addresses": "^6.8.1",
"@0x/contracts-erc20": "^3.3.22",
"@0x/contracts-gen": "^2.0.40",
"@0x/contracts-test-utils": "^5.4.13",
"@0x/dev-utils": "^4.2.9",
"@0x/abi-gen": "^5.8.0",
"@0x/contract-addresses": "^6.13.0",
"@0x/contracts-erc20": "^3.3.29",
"@0x/contracts-gen": "^2.0.46",
"@0x/contracts-test-utils": "^5.4.20",
"@0x/dev-utils": "^4.2.14",
"@0x/order-utils": "^10.4.28",
"@0x/sol-compiler": "^4.7.5",
"@0x/sol-compiler": "^4.8.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.4",
"@typechain/ethers-v5": "^10.0.0",
"@types/isomorphic-fetch": "^0.0.35",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
@@ -78,18 +80,19 @@
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typechain": "^8.0.0",
"typedoc": "~0.16.11",
"typescript": "4.2.2"
"typescript": "4.6.3"
},
"dependencies": {
"@0x/base-contract": "^6.4.2",
"@0x/protocol-utils": "^1.9.4",
"@0x/subproviders": "^6.6.0",
"@0x/types": "^3.3.4",
"@0x/typescript-typings": "^5.2.1",
"@0x/utils": "^6.4.4",
"@0x/web3-wrapper": "^7.6.0",
"ethereum-types": "^3.6.0",
"@0x/base-contract": "^6.5.0",
"@0x/protocol-utils": "^11.12.0",
"@0x/subproviders": "^6.6.5",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^6.5.3",
"@0x/web3-wrapper": "^7.6.5",
"ethereum-types": "^3.7.0",
"ethereumjs-util": "^7.0.10",
"ethers": "~4.0.4"
},

View File

@@ -11,11 +11,16 @@ import * as BootstrapFeature from '../test/generated-artifacts/BootstrapFeature.
import * as BridgeAdapter from '../test/generated-artifacts/BridgeAdapter.json';
import * as BridgeProtocols from '../test/generated-artifacts/BridgeProtocols.json';
import * as CurveLiquidityProvider from '../test/generated-artifacts/CurveLiquidityProvider.json';
import * as ERC1155OrdersFeature from '../test/generated-artifacts/ERC1155OrdersFeature.json';
import * as ERC165Feature from '../test/generated-artifacts/ERC165Feature.json';
import * as ERC721OrdersFeature from '../test/generated-artifacts/ERC721OrdersFeature.json';
import * as FeeCollector from '../test/generated-artifacts/FeeCollector.json';
import * as FeeCollectorController from '../test/generated-artifacts/FeeCollectorController.json';
import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json';
import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json';
import * as FixinEIP712 from '../test/generated-artifacts/FixinEIP712.json';
import * as FixinERC1155Spender from '../test/generated-artifacts/FixinERC1155Spender.json';
import * as FixinERC721Spender from '../test/generated-artifacts/FixinERC721Spender.json';
import * as FixinProtocolFees from '../test/generated-artifacts/FixinProtocolFees.json';
import * as FixinReentrancyGuard from '../test/generated-artifacts/FixinReentrancyGuard.json';
import * as FixinTokenSpender from '../test/generated-artifacts/FixinTokenSpender.json';
@@ -25,9 +30,15 @@ import * as FundRecoveryFeature from '../test/generated-artifacts/FundRecoveryFe
import * as IBatchFillNativeOrdersFeature from '../test/generated-artifacts/IBatchFillNativeOrdersFeature.json';
import * as IBootstrapFeature from '../test/generated-artifacts/IBootstrapFeature.json';
import * as IBridgeAdapter from '../test/generated-artifacts/IBridgeAdapter.json';
import * as IERC1155OrdersFeature from '../test/generated-artifacts/IERC1155OrdersFeature.json';
import * as IERC1155Token from '../test/generated-artifacts/IERC1155Token.json';
import * as IERC165Feature from '../test/generated-artifacts/IERC165Feature.json';
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json';
import * as IERC721OrdersFeature from '../test/generated-artifacts/IERC721OrdersFeature.json';
import * as IERC721Token from '../test/generated-artifacts/IERC721Token.json';
import * as IFeature from '../test/generated-artifacts/IFeature.json';
import * as IFeeRecipient from '../test/generated-artifacts/IFeeRecipient.json';
import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json';
import * as IFundRecoveryFeature from '../test/generated-artifacts/IFundRecoveryFeature.json';
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
@@ -42,8 +53,10 @@ import * as InitialMigration from '../test/generated-artifacts/InitialMigration.
import * as IOtcOrdersFeature from '../test/generated-artifacts/IOtcOrdersFeature.json';
import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json';
import * as IPancakeSwapFeature from '../test/generated-artifacts/IPancakeSwapFeature.json';
import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json';
import * as ISimpleFunctionRegistryFeature from '../test/generated-artifacts/ISimpleFunctionRegistryFeature.json';
import * as IStaking from '../test/generated-artifacts/IStaking.json';
import * as ITakerCallback from '../test/generated-artifacts/ITakerCallback.json';
import * as ITestSimpleFunctionRegistryFeature from '../test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json';
import * as ITokenSpenderFeature from '../test/generated-artifacts/ITokenSpenderFeature.json';
import * as ITransformERC20Feature from '../test/generated-artifacts/ITransformERC20Feature.json';
@@ -54,7 +67,9 @@ import * as IUniswapV3Pool from '../test/generated-artifacts/IUniswapV3Pool.json
import * as IZeroEx from '../test/generated-artifacts/IZeroEx.json';
import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json';
import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json';
import * as LibERC1155OrdersStorage from '../test/generated-artifacts/LibERC1155OrdersStorage.json';
import * as LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.json';
import * as LibERC721OrdersStorage from '../test/generated-artifacts/LibERC721OrdersStorage.json';
import * as LibFeeCollector from '../test/generated-artifacts/LibFeeCollector.json';
import * as LibLiquidityProviderRichErrors from '../test/generated-artifacts/LibLiquidityProviderRichErrors.json';
import * as LibMetaTransactionsRichErrors from '../test/generated-artifacts/LibMetaTransactionsRichErrors.json';
@@ -63,6 +78,8 @@ import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json';
import * as LibNativeOrder from '../test/generated-artifacts/LibNativeOrder.json';
import * as LibNativeOrdersRichErrors from '../test/generated-artifacts/LibNativeOrdersRichErrors.json';
import * as LibNativeOrdersStorage from '../test/generated-artifacts/LibNativeOrdersStorage.json';
import * as LibNFTOrder from '../test/generated-artifacts/LibNFTOrder.json';
import * as LibNFTOrdersRichErrors from '../test/generated-artifacts/LibNFTOrdersRichErrors.json';
import * as LibOtcOrdersStorage from '../test/generated-artifacts/LibOtcOrdersStorage.json';
import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json';
import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json';
@@ -81,10 +98,13 @@ import * as LiquidityProviderFeature from '../test/generated-artifacts/Liquidity
import * as LiquidityProviderSandbox from '../test/generated-artifacts/LiquidityProviderSandbox.json';
import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json';
import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json';
import * as MixinAaveV2 from '../test/generated-artifacts/MixinAaveV2.json';
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json';
import * as MixinBalancerV2Batch from '../test/generated-artifacts/MixinBalancerV2Batch.json';
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
import * as MixinCompound from '../test/generated-artifacts/MixinCompound.json';
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
import * as MixinCurveV2 from '../test/generated-artifacts/MixinCurveV2.json';
@@ -116,6 +136,7 @@ import * as NativeOrdersFeature from '../test/generated-artifacts/NativeOrdersFe
import * as NativeOrdersInfo from '../test/generated-artifacts/NativeOrdersInfo.json';
import * as NativeOrdersProtocolFees from '../test/generated-artifacts/NativeOrdersProtocolFees.json';
import * as NativeOrdersSettlement from '../test/generated-artifacts/NativeOrdersSettlement.json';
import * as NFTOrders from '../test/generated-artifacts/NFTOrders.json';
import * as OtcOrdersFeature from '../test/generated-artifacts/OtcOrdersFeature.json';
import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json';
import * as PancakeSwapFeature from '../test/generated-artifacts/PancakeSwapFeature.json';
@@ -128,6 +149,7 @@ import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.json
import * as TestCurve from '../test/generated-artifacts/TestCurve.json';
import * as TestDelegateCaller from '../test/generated-artifacts/TestDelegateCaller.json';
import * as TestFeeCollectorController from '../test/generated-artifacts/TestFeeCollectorController.json';
import * as TestFeeRecipient from '../test/generated-artifacts/TestFeeRecipient.json';
import * as TestFillQuoteTransformerBridge from '../test/generated-artifacts/TestFillQuoteTransformerBridge.json';
import * as TestFillQuoteTransformerExchange from '../test/generated-artifacts/TestFillQuoteTransformerExchange.json';
import * as TestFillQuoteTransformerHost from '../test/generated-artifacts/TestFillQuoteTransformerHost.json';
@@ -141,14 +163,18 @@ import * as TestLiquidityProvider from '../test/generated-artifacts/TestLiquidit
import * as TestMetaTransactionsNativeOrdersFeature from '../test/generated-artifacts/TestMetaTransactionsNativeOrdersFeature.json';
import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json';
import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json';
import * as TestMintableERC1155Token from '../test/generated-artifacts/TestMintableERC1155Token.json';
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
import * as TestMintableERC721Token from '../test/generated-artifacts/TestMintableERC721Token.json';
import * as TestMintTokenERC20Transformer from '../test/generated-artifacts/TestMintTokenERC20Transformer.json';
import * as TestMooniswap from '../test/generated-artifacts/TestMooniswap.json';
import * as TestNativeOrdersFeature from '../test/generated-artifacts/TestNativeOrdersFeature.json';
import * as TestNFTOrderPresigner from '../test/generated-artifacts/TestNFTOrderPresigner.json';
import * as TestNoEthRecipient from '../test/generated-artifacts/TestNoEthRecipient.json';
import * as TestOrderSignerRegistryWithContractWallet from '../test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json';
import * as TestPermissionlessTransformerDeployerSuicidal from '../test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json';
import * as TestPermissionlessTransformerDeployerTransformer from '../test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json';
import * as TestPropertyValidator from '../test/generated-artifacts/TestPropertyValidator.json';
import * as TestRfqOriginRegistration from '../test/generated-artifacts/TestRfqOriginRegistration.json';
import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json';
import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json';
@@ -181,6 +207,7 @@ export const artifacts = {
LibCommonRichErrors: LibCommonRichErrors as ContractArtifact,
LibLiquidityProviderRichErrors: LibLiquidityProviderRichErrors as ContractArtifact,
LibMetaTransactionsRichErrors: LibMetaTransactionsRichErrors as ContractArtifact,
LibNFTOrdersRichErrors: LibNFTOrdersRichErrors as ContractArtifact,
LibNativeOrdersRichErrors: LibNativeOrdersRichErrors as ContractArtifact,
LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact,
LibProxyRichErrors: LibProxyRichErrors as ContractArtifact,
@@ -199,6 +226,7 @@ export const artifacts = {
TransformerDeployer: TransformerDeployer as ContractArtifact,
BatchFillNativeOrdersFeature: BatchFillNativeOrdersFeature as ContractArtifact,
BootstrapFeature: BootstrapFeature as ContractArtifact,
ERC165Feature: ERC165Feature as ContractArtifact,
FundRecoveryFeature: FundRecoveryFeature as ContractArtifact,
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact,
@@ -212,6 +240,9 @@ export const artifacts = {
UniswapV3Feature: UniswapV3Feature as ContractArtifact,
IBatchFillNativeOrdersFeature: IBatchFillNativeOrdersFeature as ContractArtifact,
IBootstrapFeature: IBootstrapFeature as ContractArtifact,
IERC1155OrdersFeature: IERC1155OrdersFeature as ContractArtifact,
IERC165Feature: IERC165Feature as ContractArtifact,
IERC721OrdersFeature: IERC721OrdersFeature as ContractArtifact,
IFeature: IFeature as ContractArtifact,
IFundRecoveryFeature: IFundRecoveryFeature as ContractArtifact,
ILiquidityProviderFeature: ILiquidityProviderFeature as ContractArtifact,
@@ -227,6 +258,7 @@ export const artifacts = {
ITransformERC20Feature: ITransformERC20Feature as ContractArtifact,
IUniswapFeature: IUniswapFeature as ContractArtifact,
IUniswapV3Feature: IUniswapV3Feature as ContractArtifact,
LibNFTOrder: LibNFTOrder as ContractArtifact,
LibNativeOrder: LibNativeOrder as ContractArtifact,
LibSignature: LibSignature as ContractArtifact,
MultiplexFeature: MultiplexFeature as ContractArtifact,
@@ -240,8 +272,13 @@ export const artifacts = {
NativeOrdersInfo: NativeOrdersInfo as ContractArtifact,
NativeOrdersProtocolFees: NativeOrdersProtocolFees as ContractArtifact,
NativeOrdersSettlement: NativeOrdersSettlement as ContractArtifact,
ERC1155OrdersFeature: ERC1155OrdersFeature as ContractArtifact,
ERC721OrdersFeature: ERC721OrdersFeature as ContractArtifact,
NFTOrders: NFTOrders as ContractArtifact,
FixinCommon: FixinCommon as ContractArtifact,
FixinEIP712: FixinEIP712 as ContractArtifact,
FixinERC1155Spender: FixinERC1155Spender as ContractArtifact,
FixinERC721Spender: FixinERC721Spender as ContractArtifact,
FixinProtocolFees: FixinProtocolFees as ContractArtifact,
FixinReentrancyGuard: FixinReentrancyGuard as ContractArtifact,
FixinTokenSpender: FixinTokenSpender as ContractArtifact,
@@ -251,6 +288,8 @@ export const artifacts = {
InitialMigration: InitialMigration as ContractArtifact,
LibBootstrap: LibBootstrap as ContractArtifact,
LibMigrate: LibMigrate as ContractArtifact,
LibERC1155OrdersStorage: LibERC1155OrdersStorage as ContractArtifact,
LibERC721OrdersStorage: LibERC721OrdersStorage as ContractArtifact,
LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact,
LibNativeOrdersStorage: LibNativeOrdersStorage as ContractArtifact,
LibOtcOrdersStorage: LibOtcOrdersStorage as ContractArtifact,
@@ -272,10 +311,13 @@ export const artifacts = {
BridgeAdapter: BridgeAdapter as ContractArtifact,
BridgeProtocols: BridgeProtocols as ContractArtifact,
IBridgeAdapter: IBridgeAdapter as ContractArtifact,
MixinAaveV2: MixinAaveV2 as ContractArtifact,
MixinBalancer: MixinBalancer as ContractArtifact,
MixinBalancerV2: MixinBalancerV2 as ContractArtifact,
MixinBalancerV2Batch: MixinBalancerV2Batch as ContractArtifact,
MixinBancor: MixinBancor as ContractArtifact,
MixinCoFiX: MixinCoFiX as ContractArtifact,
MixinCompound: MixinCompound as ContractArtifact,
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
MixinCurve: MixinCurve as ContractArtifact,
MixinCurveV2: MixinCurveV2 as ContractArtifact,
@@ -294,8 +336,13 @@ export const artifacts = {
MixinUniswapV2: MixinUniswapV2 as ContractArtifact,
MixinUniswapV3: MixinUniswapV3 as ContractArtifact,
MixinZeroExBridge: MixinZeroExBridge as ContractArtifact,
IERC1155Token: IERC1155Token as ContractArtifact,
IERC721Token: IERC721Token as ContractArtifact,
IFeeRecipient: IFeeRecipient as ContractArtifact,
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
IMooniswapPool: IMooniswapPool as ContractArtifact,
IPropertyValidator: IPropertyValidator as ContractArtifact,
ITakerCallback: ITakerCallback as ContractArtifact,
IUniswapV2Pair: IUniswapV2Pair as ContractArtifact,
IUniswapV3Pool: IUniswapV3Pool as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
@@ -303,9 +350,9 @@ export const artifacts = {
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
TestBridge: TestBridge as ContractArtifact,
TestCallTarget: TestCallTarget as ContractArtifact,
TestCurve: TestCurve as ContractArtifact,
TestDelegateCaller: TestDelegateCaller as ContractArtifact,
TestFeeCollectorController: TestFeeCollectorController as ContractArtifact,
TestFeeRecipient: TestFeeRecipient as ContractArtifact,
TestFillQuoteTransformerBridge: TestFillQuoteTransformerBridge as ContractArtifact,
TestFillQuoteTransformerExchange: TestFillQuoteTransformerExchange as ContractArtifact,
TestFillQuoteTransformerHost: TestFillQuoteTransformerHost as ContractArtifact,
@@ -315,33 +362,38 @@ export const artifacts = {
TestInitialMigration: TestInitialMigration as ContractArtifact,
TestLibNativeOrder: TestLibNativeOrder as ContractArtifact,
TestLibSignature: TestLibSignature as ContractArtifact,
TestLiquidityProvider: TestLiquidityProvider as ContractArtifact,
TestMetaTransactionsNativeOrdersFeature: TestMetaTransactionsNativeOrdersFeature as ContractArtifact,
TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact,
TestMigrator: TestMigrator as ContractArtifact,
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
TestMintableERC20Token: TestMintableERC20Token as ContractArtifact,
TestMooniswap: TestMooniswap as ContractArtifact,
TestNFTOrderPresigner: TestNFTOrderPresigner as ContractArtifact,
TestNativeOrdersFeature: TestNativeOrdersFeature as ContractArtifact,
TestNoEthRecipient: TestNoEthRecipient as ContractArtifact,
TestOrderSignerRegistryWithContractWallet: TestOrderSignerRegistryWithContractWallet as ContractArtifact,
TestPermissionlessTransformerDeployerSuicidal: TestPermissionlessTransformerDeployerSuicidal as ContractArtifact,
TestPermissionlessTransformerDeployerTransformer: TestPermissionlessTransformerDeployerTransformer as ContractArtifact,
TestPropertyValidator: TestPropertyValidator as ContractArtifact,
TestRfqOriginRegistration: TestRfqOriginRegistration as ContractArtifact,
TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact,
TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact,
TestStaking: TestStaking as ContractArtifact,
TestTokenSpenderERC20Token: TestTokenSpenderERC20Token as ContractArtifact,
TestTransformERC20: TestTransformERC20 as ContractArtifact,
TestTransformerBase: TestTransformerBase as ContractArtifact,
TestTransformerDeployerTransformer: TestTransformerDeployerTransformer as ContractArtifact,
TestTransformerHost: TestTransformerHost as ContractArtifact,
TestUniswapV3Feature: TestUniswapV3Feature as ContractArtifact,
TestWethTransformerHost: TestWethTransformerHost as ContractArtifact,
TestZeroExFeature: TestZeroExFeature as ContractArtifact,
TestCurve: TestCurve as ContractArtifact,
TestLiquidityProvider: TestLiquidityProvider as ContractArtifact,
TestMooniswap: TestMooniswap as ContractArtifact,
TestUniswapV2Factory: TestUniswapV2Factory as ContractArtifact,
TestUniswapV2Pool: TestUniswapV2Pool as ContractArtifact,
TestUniswapV3Factory: TestUniswapV3Factory as ContractArtifact,
TestUniswapV3Feature: TestUniswapV3Feature as ContractArtifact,
TestUniswapV3Pool: TestUniswapV3Pool as ContractArtifact,
TestMintableERC1155Token: TestMintableERC1155Token as ContractArtifact,
TestMintableERC20Token: TestMintableERC20Token as ContractArtifact,
TestMintableERC721Token: TestMintableERC721Token as ContractArtifact,
TestTokenSpenderERC20Token: TestTokenSpenderERC20Token as ContractArtifact,
TestWeth: TestWeth as ContractArtifact,
TestWethTransformerHost: TestWethTransformerHost as ContractArtifact,
TestZeroExFeature: TestZeroExFeature as ContractArtifact,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
let nativeOrdersFeature: TestMetaTransactionsNativeOrdersFeatureContract;
const MAX_FEE_AMOUNT = new BigNumber('1e18');
const TRANSFORM_ERC20_ONE_WEI_VALUE = new BigNumber(555);
const TRANSFORM_ERC20_FAILING_VALUE = new BigNumber(666);
const TRANSFORM_ERC20_REENTER_VALUE = new BigNumber(777);
const TRANSFORM_ERC20_BATCH_REENTER_VALUE = new BigNumber(888);
@@ -597,7 +598,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
);
});
it('cannot reenter `executeMetaTransaction()`', async () => {
it('cannot reduce initial ETH balance', async () => {
const args = getRandomTransformERC20Args();
const mtx = getRandomMetaTransaction({
callData: transformERC20Feature
@@ -609,58 +610,23 @@ blockchainTests.resets('MetaTransactions feature', env => {
args.transformations,
)
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_REENTER_VALUE,
value: TRANSFORM_ERC20_ONE_WEI_VALUE,
});
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
};
const tx = feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
return expect(tx).to.revertWith(
new ZeroExRevertErrors.MetaTransactions.MetaTransactionCallFailedError(
mtxHash,
undefined,
new ZeroExRevertErrors.Common.IllegalReentrancyError(
feature.getSelector('executeMetaTransaction'),
REENTRANCY_FLAG_MTX,
).encode(),
),
// Send pre-existing ETH to the EP.
await env.web3Wrapper.awaitTransactionSuccessAsync(
await env.web3Wrapper.sendTransactionAsync({
from: owner,
to: zeroEx.address,
value: new BigNumber(1),
}),
);
});
it('cannot reenter `batchExecuteMetaTransactions()`', async () => {
const args = getRandomTransformERC20Args();
const mtx = getRandomMetaTransaction({
callData: transformERC20Feature
.transformERC20(
args.inputToken,
args.outputToken,
args.inputTokenAmount,
args.minOutputTokenAmount,
args.transformations,
)
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_BATCH_REENTER_VALUE,
});
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
};
const tx = feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
return expect(tx).to.revertWith(
new ZeroExRevertErrors.MetaTransactions.MetaTransactionCallFailedError(
mtxHash,
undefined,
new ZeroExRevertErrors.Common.IllegalReentrancyError(
feature.getSelector('batchExecuteMetaTransactions'),
REENTRANCY_FLAG_MTX,
).encode(),
),
);
return expect(tx).to.revertWith('MetaTransactionsFeature/ETH_LEAK');
});
});
@@ -817,6 +783,37 @@ blockchainTests.resets('MetaTransactions feature', env => {
),
);
});
it('cannot reduce initial ETH balance', async () => {
const args = getRandomTransformERC20Args();
const mtx = getRandomMetaTransaction({
callData: transformERC20Feature
.transformERC20(
args.inputToken,
args.outputToken,
args.inputTokenAmount,
args.minOutputTokenAmount,
args.transformations,
)
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_ONE_WEI_VALUE,
});
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
};
// Send pre-existing ETH to the EP.
await env.web3Wrapper.awaitTransactionSuccessAsync(
await env.web3Wrapper.sendTransactionAsync({
from: owner,
to: zeroEx.address,
value: new BigNumber(1),
}),
);
const tx = feature.batchExecuteMetaTransactions([mtx], [signature]).awaitTransactionSuccessAsync(callOpts);
return expect(tx).to.revertWith('MetaTransactionsFeature/ETH_LEAK');
});
});
describe('getMetaTransactionExecutedBlock()', () => {

View File

@@ -0,0 +1,41 @@
import { constants, getRandomInteger, randomAddress } from '@0x/contracts-test-utils';
import { ERC1155Order, ERC721Order } from '@0x/protocol-utils';
import { BigNumber } from '@0x/utils';
/**
* Generate a random ERC721 Order
*/
export function getRandomERC721Order(fields: Partial<ERC721Order> = {}): ERC721Order {
return new ERC721Order({
erc20Token: randomAddress(),
erc20TokenAmount: getRandomInteger('1e18', '10e18'),
erc721Token: randomAddress(),
erc721TokenId: getRandomInteger(0, constants.MAX_UINT256),
maker: randomAddress(),
taker: randomAddress(),
erc721TokenProperties: [],
fees: [],
nonce: getRandomInteger(0, constants.MAX_UINT256),
expiry: new BigNumber(Math.floor(Date.now() / 1000 + 60)),
...fields,
});
}
/**
* Generate a random ERC1155 Order
*/
export function getRandomERC1155Order(fields: Partial<ERC1155Order> = {}): ERC1155Order {
return new ERC1155Order({
erc20Token: randomAddress(),
erc20TokenAmount: getRandomInteger('1e18', '10e18'),
erc1155Token: randomAddress(),
erc1155TokenId: getRandomInteger(0, constants.MAX_UINT256),
erc1155TokenAmount: getRandomInteger(1, '10e18'),
maker: randomAddress(),
taker: randomAddress(),
erc1155TokenProperties: [],
fees: [],
nonce: getRandomInteger(0, constants.MAX_UINT256),
expiry: new BigNumber(Math.floor(Date.now() / 1000 + 60)),
...fields,
});
}

View File

@@ -9,11 +9,16 @@ export * from '../test/generated-wrappers/bootstrap_feature';
export * from '../test/generated-wrappers/bridge_adapter';
export * from '../test/generated-wrappers/bridge_protocols';
export * from '../test/generated-wrappers/curve_liquidity_provider';
export * from '../test/generated-wrappers/erc1155_orders_feature';
export * from '../test/generated-wrappers/erc165_feature';
export * from '../test/generated-wrappers/erc721_orders_feature';
export * from '../test/generated-wrappers/fee_collector';
export * from '../test/generated-wrappers/fee_collector_controller';
export * from '../test/generated-wrappers/fill_quote_transformer';
export * from '../test/generated-wrappers/fixin_common';
export * from '../test/generated-wrappers/fixin_e_i_p712';
export * from '../test/generated-wrappers/fixin_erc1155_spender';
export * from '../test/generated-wrappers/fixin_erc721_spender';
export * from '../test/generated-wrappers/fixin_protocol_fees';
export * from '../test/generated-wrappers/fixin_reentrancy_guard';
export * from '../test/generated-wrappers/fixin_token_spender';
@@ -23,9 +28,15 @@ export * from '../test/generated-wrappers/fund_recovery_feature';
export * from '../test/generated-wrappers/i_batch_fill_native_orders_feature';
export * from '../test/generated-wrappers/i_bootstrap_feature';
export * from '../test/generated-wrappers/i_bridge_adapter';
export * from '../test/generated-wrappers/i_erc1155_orders_feature';
export * from '../test/generated-wrappers/i_erc1155_token';
export * from '../test/generated-wrappers/i_erc165_feature';
export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_erc20_transformer';
export * from '../test/generated-wrappers/i_erc721_orders_feature';
export * from '../test/generated-wrappers/i_erc721_token';
export * from '../test/generated-wrappers/i_feature';
export * from '../test/generated-wrappers/i_fee_recipient';
export * from '../test/generated-wrappers/i_flash_wallet';
export * from '../test/generated-wrappers/i_fund_recovery_feature';
export * from '../test/generated-wrappers/i_liquidity_provider';
@@ -39,8 +50,10 @@ export * from '../test/generated-wrappers/i_native_orders_feature';
export * from '../test/generated-wrappers/i_otc_orders_feature';
export * from '../test/generated-wrappers/i_ownable_feature';
export * from '../test/generated-wrappers/i_pancake_swap_feature';
export * from '../test/generated-wrappers/i_property_validator';
export * from '../test/generated-wrappers/i_simple_function_registry_feature';
export * from '../test/generated-wrappers/i_staking';
export * from '../test/generated-wrappers/i_taker_callback';
export * from '../test/generated-wrappers/i_test_simple_function_registry_feature';
export * from '../test/generated-wrappers/i_token_spender_feature';
export * from '../test/generated-wrappers/i_transform_erc20_feature';
@@ -52,12 +65,16 @@ export * from '../test/generated-wrappers/i_zero_ex';
export * from '../test/generated-wrappers/initial_migration';
export * from '../test/generated-wrappers/lib_bootstrap';
export * from '../test/generated-wrappers/lib_common_rich_errors';
export * from '../test/generated-wrappers/lib_erc1155_orders_storage';
export * from '../test/generated-wrappers/lib_erc20_transformer';
export * from '../test/generated-wrappers/lib_erc721_orders_storage';
export * from '../test/generated-wrappers/lib_fee_collector';
export * from '../test/generated-wrappers/lib_liquidity_provider_rich_errors';
export * from '../test/generated-wrappers/lib_meta_transactions_rich_errors';
export * from '../test/generated-wrappers/lib_meta_transactions_storage';
export * from '../test/generated-wrappers/lib_migrate';
export * from '../test/generated-wrappers/lib_n_f_t_order';
export * from '../test/generated-wrappers/lib_n_f_t_orders_rich_errors';
export * from '../test/generated-wrappers/lib_native_order';
export * from '../test/generated-wrappers/lib_native_orders_rich_errors';
export * from '../test/generated-wrappers/lib_native_orders_storage';
@@ -79,10 +96,13 @@ export * from '../test/generated-wrappers/liquidity_provider_feature';
export * from '../test/generated-wrappers/liquidity_provider_sandbox';
export * from '../test/generated-wrappers/log_metadata_transformer';
export * from '../test/generated-wrappers/meta_transactions_feature';
export * from '../test/generated-wrappers/mixin_aave_v2';
export * from '../test/generated-wrappers/mixin_balancer';
export * from '../test/generated-wrappers/mixin_balancer_v2';
export * from '../test/generated-wrappers/mixin_balancer_v2_batch';
export * from '../test/generated-wrappers/mixin_bancor';
export * from '../test/generated-wrappers/mixin_co_fi_x';
export * from '../test/generated-wrappers/mixin_compound';
export * from '../test/generated-wrappers/mixin_crypto_com';
export * from '../test/generated-wrappers/mixin_curve';
export * from '../test/generated-wrappers/mixin_curve_v2';
@@ -109,6 +129,7 @@ export * from '../test/generated-wrappers/multiplex_rfq';
export * from '../test/generated-wrappers/multiplex_transform_erc20';
export * from '../test/generated-wrappers/multiplex_uniswap_v2';
export * from '../test/generated-wrappers/multiplex_uniswap_v3';
export * from '../test/generated-wrappers/n_f_t_orders';
export * from '../test/generated-wrappers/native_orders_cancellation';
export * from '../test/generated-wrappers/native_orders_feature';
export * from '../test/generated-wrappers/native_orders_info';
@@ -126,6 +147,7 @@ export * from '../test/generated-wrappers/test_call_target';
export * from '../test/generated-wrappers/test_curve';
export * from '../test/generated-wrappers/test_delegate_caller';
export * from '../test/generated-wrappers/test_fee_collector_controller';
export * from '../test/generated-wrappers/test_fee_recipient';
export * from '../test/generated-wrappers/test_fill_quote_transformer_bridge';
export * from '../test/generated-wrappers/test_fill_quote_transformer_exchange';
export * from '../test/generated-wrappers/test_fill_quote_transformer_host';
@@ -140,13 +162,17 @@ export * from '../test/generated-wrappers/test_meta_transactions_native_orders_f
export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20_feature';
export * from '../test/generated-wrappers/test_migrator';
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
export * from '../test/generated-wrappers/test_mintable_erc1155_token';
export * from '../test/generated-wrappers/test_mintable_erc20_token';
export * from '../test/generated-wrappers/test_mintable_erc721_token';
export * from '../test/generated-wrappers/test_mooniswap';
export * from '../test/generated-wrappers/test_n_f_t_order_presigner';
export * from '../test/generated-wrappers/test_native_orders_feature';
export * from '../test/generated-wrappers/test_no_eth_recipient';
export * from '../test/generated-wrappers/test_order_signer_registry_with_contract_wallet';
export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_suicidal';
export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_transformer';
export * from '../test/generated-wrappers/test_property_validator';
export * from '../test/generated-wrappers/test_rfq_origin_registration';
export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl1';
export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl2';

View File

@@ -42,11 +42,16 @@
"test/generated-artifacts/BridgeAdapter.json",
"test/generated-artifacts/BridgeProtocols.json",
"test/generated-artifacts/CurveLiquidityProvider.json",
"test/generated-artifacts/ERC1155OrdersFeature.json",
"test/generated-artifacts/ERC165Feature.json",
"test/generated-artifacts/ERC721OrdersFeature.json",
"test/generated-artifacts/FeeCollector.json",
"test/generated-artifacts/FeeCollectorController.json",
"test/generated-artifacts/FillQuoteTransformer.json",
"test/generated-artifacts/FixinCommon.json",
"test/generated-artifacts/FixinEIP712.json",
"test/generated-artifacts/FixinERC1155Spender.json",
"test/generated-artifacts/FixinERC721Spender.json",
"test/generated-artifacts/FixinProtocolFees.json",
"test/generated-artifacts/FixinReentrancyGuard.json",
"test/generated-artifacts/FixinTokenSpender.json",
@@ -56,9 +61,15 @@
"test/generated-artifacts/IBatchFillNativeOrdersFeature.json",
"test/generated-artifacts/IBootstrapFeature.json",
"test/generated-artifacts/IBridgeAdapter.json",
"test/generated-artifacts/IERC1155OrdersFeature.json",
"test/generated-artifacts/IERC1155Token.json",
"test/generated-artifacts/IERC165Feature.json",
"test/generated-artifacts/IERC20Bridge.json",
"test/generated-artifacts/IERC20Transformer.json",
"test/generated-artifacts/IERC721OrdersFeature.json",
"test/generated-artifacts/IERC721Token.json",
"test/generated-artifacts/IFeature.json",
"test/generated-artifacts/IFeeRecipient.json",
"test/generated-artifacts/IFlashWallet.json",
"test/generated-artifacts/IFundRecoveryFeature.json",
"test/generated-artifacts/ILiquidityProvider.json",
@@ -72,8 +83,10 @@
"test/generated-artifacts/IOtcOrdersFeature.json",
"test/generated-artifacts/IOwnableFeature.json",
"test/generated-artifacts/IPancakeSwapFeature.json",
"test/generated-artifacts/IPropertyValidator.json",
"test/generated-artifacts/ISimpleFunctionRegistryFeature.json",
"test/generated-artifacts/IStaking.json",
"test/generated-artifacts/ITakerCallback.json",
"test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json",
"test/generated-artifacts/ITokenSpenderFeature.json",
"test/generated-artifacts/ITransformERC20Feature.json",
@@ -85,12 +98,16 @@
"test/generated-artifacts/InitialMigration.json",
"test/generated-artifacts/LibBootstrap.json",
"test/generated-artifacts/LibCommonRichErrors.json",
"test/generated-artifacts/LibERC1155OrdersStorage.json",
"test/generated-artifacts/LibERC20Transformer.json",
"test/generated-artifacts/LibERC721OrdersStorage.json",
"test/generated-artifacts/LibFeeCollector.json",
"test/generated-artifacts/LibLiquidityProviderRichErrors.json",
"test/generated-artifacts/LibMetaTransactionsRichErrors.json",
"test/generated-artifacts/LibMetaTransactionsStorage.json",
"test/generated-artifacts/LibMigrate.json",
"test/generated-artifacts/LibNFTOrder.json",
"test/generated-artifacts/LibNFTOrdersRichErrors.json",
"test/generated-artifacts/LibNativeOrder.json",
"test/generated-artifacts/LibNativeOrdersRichErrors.json",
"test/generated-artifacts/LibNativeOrdersStorage.json",
@@ -112,10 +129,13 @@
"test/generated-artifacts/LiquidityProviderSandbox.json",
"test/generated-artifacts/LogMetadataTransformer.json",
"test/generated-artifacts/MetaTransactionsFeature.json",
"test/generated-artifacts/MixinAaveV2.json",
"test/generated-artifacts/MixinBalancer.json",
"test/generated-artifacts/MixinBalancerV2.json",
"test/generated-artifacts/MixinBalancerV2Batch.json",
"test/generated-artifacts/MixinBancor.json",
"test/generated-artifacts/MixinCoFiX.json",
"test/generated-artifacts/MixinCompound.json",
"test/generated-artifacts/MixinCryptoCom.json",
"test/generated-artifacts/MixinCurve.json",
"test/generated-artifacts/MixinCurveV2.json",
@@ -142,6 +162,7 @@
"test/generated-artifacts/MultiplexTransformERC20.json",
"test/generated-artifacts/MultiplexUniswapV2.json",
"test/generated-artifacts/MultiplexUniswapV3.json",
"test/generated-artifacts/NFTOrders.json",
"test/generated-artifacts/NativeOrdersCancellation.json",
"test/generated-artifacts/NativeOrdersFeature.json",
"test/generated-artifacts/NativeOrdersInfo.json",
@@ -159,6 +180,7 @@
"test/generated-artifacts/TestCurve.json",
"test/generated-artifacts/TestDelegateCaller.json",
"test/generated-artifacts/TestFeeCollectorController.json",
"test/generated-artifacts/TestFeeRecipient.json",
"test/generated-artifacts/TestFillQuoteTransformerBridge.json",
"test/generated-artifacts/TestFillQuoteTransformerExchange.json",
"test/generated-artifacts/TestFillQuoteTransformerHost.json",
@@ -173,13 +195,17 @@
"test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json",
"test/generated-artifacts/TestMigrator.json",
"test/generated-artifacts/TestMintTokenERC20Transformer.json",
"test/generated-artifacts/TestMintableERC1155Token.json",
"test/generated-artifacts/TestMintableERC20Token.json",
"test/generated-artifacts/TestMintableERC721Token.json",
"test/generated-artifacts/TestMooniswap.json",
"test/generated-artifacts/TestNFTOrderPresigner.json",
"test/generated-artifacts/TestNativeOrdersFeature.json",
"test/generated-artifacts/TestNoEthRecipient.json",
"test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json",
"test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json",
"test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json",
"test/generated-artifacts/TestPropertyValidator.json",
"test/generated-artifacts/TestRfqOriginRegistration.json",
"test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json",
"test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json",

View File

@@ -4,23 +4,28 @@ Audits
Below are links to our third-party audit reports.
+------------------+---------------------------------------------------------------------------------------------------------------+
| **Release** | **Reports** |
+------------------+---------------------------------------------------------------------------------------------------------------+
| Exchange V4 | * `Consensys Diligence (December 2020) <https://consensys.net/diligence/audits/2020/12/0x-exchange-v4/>`__ |
+------------------+---------------------------------------------------------------------------------------------------------------+
| Exchange V3 | * `Trail of Bits <http://zeips.0x.org.s3-website.us-east-2.amazonaws.com/audits/56/trail-of-bits/audit.pdf>`_ |
| | * `Consensys Diligence (Exchange) <https://diligence.consensys.net/audits/2019/09/0x-v3-exchange/>`__ |
| | * `Consensys Diligence (Staking) <https://diligence.consensys.net/audits/2019/10/0x-v3-staking/>`__ |
+------------------+---------------------------------------------------------------------------------------------------------------+
| Exchange V2.1 | * `First <https://docs.google.com/document/d/1jYv6V21MfCSwCS5fxD6ZyaLWGzkpRSUO0lZpST94XsA/edit>`_ |
| | * `Consensys Diligence <https://github.com/ConsenSys/0x_audit_report_2018-07-23>`_ |
+------------------+---------------------------------------------------------------------------------------------------------------+
| MultiAssetProxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2018-12>`__ |
+------------------+---------------------------------------------------------------------------------------------------------------+
| ERC1155Proxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2019-05>`__ |
+------------------+---------------------------------------------------------------------------------------------------------------+
| StaticCallProxy | * No third-party audit. |
+------------------+---------------------------------------------------------------------------------------------------------------+
| ERC20BridgeProxy | * No third-party audit. |
+------------------+---------------------------------------------------------------------------------------------------------------+
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| **Release** | **Reports** |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| ERC721OrdersFeature | * `ABDK Consulting <https://s3.us-east-2.amazonaws.com/zeips.0x.org/audits/abdk-consulting/ABDK_0x_Solidity_v_1_0.pdf>`__ |
| | |
| | |
| ERC1155OrdersFeature | |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| Exchange V4 | * `Consensys Diligence (December 2020) <https://consensys.net/diligence/audits/2020/12/0x-exchange-v4/>`__ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| Exchange V3 | * `Trail of Bits <http://zeips.0x.org.s3-website.us-east-2.amazonaws.com/audits/56/trail-of-bits/audit.pdf>`__ |
| | * `Consensys Diligence (Exchange) <https://diligence.consensys.net/audits/2019/09/0x-v3-exchange/>`__ |
| | * `Consensys Diligence (Staking) <https://diligence.consensys.net/audits/2019/10/0x-v3-staking/>`__ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| Exchange V2.1 | * `First <https://docs.google.com/document/d/1jYv6V21MfCSwCS5fxD6ZyaLWGzkpRSUO0lZpST94XsA/edit>`_ |
| | * `Consensys Diligence <https://github.com/ConsenSys/0x_audit_report_2018-07-23>`_ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| MultiAssetProxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2018-12>`__ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| ERC1155Proxy | * `Consensys Diligence <https://github.com/ConsenSys/0x-audit-report-2019-05>`__ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| StaticCallProxy | * No third-party audit. |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+
| ERC20BridgeProxy | * No third-party audit. |
+----------------------+---------------------------------------------------------------------------------------------------------------------------+

View File

@@ -2,47 +2,15 @@
Bounties
###############################
We run an ongoing bug bounty for the 0x Protocol smart contracts! The program is open to anyone and
rewards up to **$100,000 for critical exploits**. The scope and disclosure instructions are below.
Rewards
-------
The severity of reported vulnerabilities will be graded according to the `CVSS <https://www.first.org/cvss/>`_ (Common Vulnerability Scoring Standard).
The following table will serve as a guideline for reward decisions:
The bug bounties on this page apply only to the *0x smart contracts* on Ethereum mainnet, Binance Smart Chain, Polygon, Avalanche, Fantom, Celo, Optimism and future deployments in other EVM-compatible networks announced through our official communication channels.
+----------------------------+---------------------+
| **Exploit Score** | **Reward** |
+----------------------------+---------------------+
| Critical (CVSS 9.0 - 10.0) | $10,000 - $100,000 |
+----------------------------+---------------------+
| High (CVSS 7.0 - 8.9) | $2,500 - $10,000 |
+----------------------------+---------------------+
| Medium (CVSS 4.0 - 6.9) | $1,000 - $2,500 |
+----------------------------+---------------------+
| Low (CVSS 0.0 - 3.9) | $0 - $1,000 |
+----------------------------+---------------------+
Bug reports pertaining to 0x API and 0x web interfaces (e.g. Matcha, 0x.org), both in terms of UI/UX or servers/infrastructure, are not eligible. Only the first reporter of a given contract vulnerability will be rewarded, and findings already discovered as part of a formal audit are ineligible.
Please note that any rewards will ultimately be awarded at the discretion of ZeroEx Intl. All rewards will be paid out in ZRX.
Overview
--------
Areas of Interest
-----------------
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| **Area** | **Examples** |
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Loss of funds | * A user loses funds in a way that they did not explicitly authorize (e.g an account is able to gain access to an ``AssetProxy`` and drain user funds). |
| | * A user authorized a transaction or trade but spends more assets than normally expected (e.g an order is allowed to be over-filled). |
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Unintended contract state | * A user is able to update the state of a contract such that it is no longer useable (e.g permanently lock a mutex). |
| | * Any assets get unexpectedly "stuck" in a contract with regular use of the contract's public methods. |
| | * An action taken in the staking contracts is applied to an incorrect epoch. |
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Bypassing time locks | * The ``ZeroExGovernor`` is allowed to bypass the timelock for transactions where it is not explicitly allowed to do so. |
| | * A user is allowed to bypass the ``ZeroExGovernor``. |
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Incorrect math | * Overflows or underflow result in unexpected behavior. |
| | * The staking reward payouts are incorrect. |
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
0x has completed smart contract audits with Consensys Diligence, Trail of Bits and ABDK. We run a continuous bug bounty program for the V4 release of the 0x core contracts.
Scope
-----
@@ -51,14 +19,14 @@ The following contracts are in scope of the bug bounty. Please note that any bug
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
| **Release** | **Contracts** | **Commit Hash** |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
| Exchange V4 | * Documentation at `https://0xprotocol.readthedocs.io/en/latest/ <https://0xprotocol.readthedocs.io/en/latest/>`__ | `72a74e7c66 <https://github.com/0xProject/protocol/tree/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src>`__ |
| | * `ZeroEx.sol <https://github.com/0xProject/protocol/blob/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src/ZeroEx.sol>`__ | |
| | * `ZeroExOptimized.sol <https://github.com/0xProject/protocol/blob/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src/ZeroExOptimized.sol>`__ | |
| | * `external/*.sol <https://github.com/0xProject/protocol/tree/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src/external>`__ | |
| | * `features/**.sol <https://github.com/0xProject/protocol/tree/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src/features>`__ | |
| | * `fixins/*.sol <https://github.com/0xProject/protocol/tree/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src/fixins>`__ | |
| | * `migrations/*.sol <https://github.com/0xProject/protocol/tree/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src/migrations>`__ | |
| | * `storage/*.sol <https://github.com/0xProject/protocol/tree/72a74e7c66e27da02dd9f4ce604ad057c740c304/contracts/zero-ex/contracts/src/storage>`__ | |
| Exchange V4 | * Documentation at `https://protocol.0x.org/en/latest/ <https://protocol.0x.org/en/latest/>`__ | `2cbeb9c <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src>`__ |
| | * `ZeroEx.sol <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src/ZeroEx.sol>`__ | |
| | * `ZeroExOptimized.sol <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src/ZeroExOptimized.sol>`__ | |
| | * `external/*.sol <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src/external>`__ | |
| | * `features/**.sol <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src/features>`__ | |
| | * `fixins/*.sol <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src/fixins>`__ | |
| | * `migrations/*.sol <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src/migrations>`__ | |
| | * `storage/*.sol <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src/storage>`__ | |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
| Exchange V3 | * `ERC20BridgeProxy.sol <https://github.com/0xProject/0x-monorepo/blob/fb8360edfd4f42f2d2b127b95c156eb1b0daa02b/contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol>`_ (`spec <https://github.com/0xProject/0x-protocol-specification/blob/master/asset-proxy/erc20-bridge-proxy.md>`__) | `fb8360edfd <https://github.com/0xProject/0x-monorepo/tree/fb8360edfd4f42f2d2b127b95c156eb1b0daa02b/contracts>`__ |
| | * `Exchange.sol <https://github.com/0xProject/0x-monorepo/blob/fb8360edfd4f42f2d2b127b95c156eb1b0daa02b/contracts/exchange/contracts/src/Exchange.sol>`__ (`spec <https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md>`__) | |
@@ -67,7 +35,7 @@ The following contracts are in scope of the bug bounty. Please note that any bug
| | * `StakingProxy.sol <https://github.com/0xProject/0x-monorepo/blob/fb8360edfd4f42f2d2b127b95c156eb1b0daa02b/contracts/staking/contracts/src/StakingProxy.sol>`_ (`spec <https://github.com/0xProject/0x-protocol-specification/blob/master/staking/staking-specification.md>`__) | |
| | * `ZrxVault.sol <https://github.com/0xProject/0x-monorepo/blob/fb8360edfd4f42f2d2b127b95c156eb1b0daa02b/contracts/staking/contracts/src/ZrxVault.sol>`_ (`spec <https://github.com/0xProject/0x-protocol-specification/blob/master/staking/staking-specification.md>`__) | |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
| Exchange V2.1 | * `src/2.0.0/protocol <https://github.com/0xProject/0x-monorepo/tree/ff70c5ecfe28eff14e1a372c5e493b8f5363e1d0/packages/contracts/src/2.0.0/protocol>`_ | `ff70c5ecfe <https://github.com/0xProject/0x-monorepo/tree/ff70c5ecfe28eff14e1a372c5e493b8f5363e1d0/contracts>`_ |
| Exchange V2.1 | * `src/2.0.0/protocol <https://github.com/0xProject/0x-monorepo/tree/ff70c5ecfe28eff14e1a372c5e493b8f5363e1d0/packages/contracts/src/2.0.0/protocol>`_ | `ff70c5ecfe <https://github.com/0xProject/0x-monorepo/tree/ff70c5ecfe28eff14e1a372c5e493b8f5363e1d0/packages/contracts/src/2.0.0>`_ |
| | * `src/2.0.0/utils <https://github.com/0xProject/0x-monorepo/tree/ff70c5ecfe28eff14e1a372c5e493b8f5363e1d0/packages/contracts/src/2.0.0/utils>`_ | |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
| MultiAssetProxy | * `MultiAssetProxy.sol <https://github.com/0xProject/0x-monorepo/blob/c4d9ef9f83508154fe9db35796b6b86aeb0f2240/contracts/asset-proxy/contracts/src/MultiAssetProxy.sol>`_ | `c4d9ef9f83 <https://github.com/0xProject/0x-monorepo/tree/c4d9ef9f83508154fe9db35796b6b86aeb0f2240/contracts>`_ |
@@ -78,9 +46,37 @@ The following contracts are in scope of the bug bounty. Please note that any bug
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
| ERC20BridgeProxy | * `ERC20BridgeProxy.sol <https://github.com/0xProject/0x-monorepo/blob/281658ba349a2c5088b40b503998bea5020284a6/contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol>`__ | `281658ba34 <https://github.com/0xProject/0x-monorepo/tree/281658ba349a2c5088b40b503998bea5020284a6/contracts>`_ |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
| ExchangeProxy | * `contracts/src <https://github.com/0xProject/0x-monorepo/tree/7967a8416c76e34ff5a0a4eb80e7b33ff8c0e297/contracts/zero-ex>`__ | `7967a8416c <https://github.com/0xProject/0x-monorepo/tree/7967a8416c76e34ff5a0a4eb80e7b33ff8c0e297/contracts>`_ |
| ExchangeProxy | * `contracts/src <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src>`__ | `2cbeb9c <https://github.com/0xProject/protocol/tree/audit/nft-orders-address-findings/contracts/zero-ex/contracts/src>`_ |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
Bounties
--------
The bounty program will pay out rewards according to the severity of a vulnerability. The severity of reported vulnerabilities will be graded according to the `CVSS <https://www.first.org/cvss/>`__ (Common Vulnerability Scoring Standard).
The final reward amount is at the sole discretion of 0x Labs and will be paid in the specified sum in either USD or ETH.
+----------------------------+---------------------+
| **Exploit Score** | **Reward** |
+----------------------------+---------------------+
| Critical (CVSS 9.0 - 10.0) | up to $1,000,000 |
+----------------------------+---------------------+
| High (CVSS 7.0 - 8.9) | up to $350,000 |
+----------------------------+---------------------+
| Medium (CVSS 4.0 - 6.9) | up to $35,000 |
+----------------------------+---------------------+
| Low (CVSS 0.0 - 3.9) | up to $5,000 |
+----------------------------+---------------------+
Recent Inclusions
-----------------
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| **Change** | **** |
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| NFT feature | * Trade ERC721 and ERC1155 assets. See `ZEIP-93 <https://github.com/0xProject/ZEIPs/issues/93>`__ for more details |
+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
Disclosures
-----------
Please e-mail all submissions to security@0x.org with the subject "BUG BOUNTY". Your submission

View File

@@ -17,3 +17,10 @@ Known tokens:
- LINK
- sUSD
- USDT
Tokens with Fees on Transfer
----------------------------
These tokens do not follow the ERC20 specification. As such the protocol expects the transfer to transfer
the specified amount, or revert. Since tokens with transfer fees do not meet this criteria, the behaviour
of the protocol with these tokens is unspecified. In most cases it will result in an overall transaction failure
due to various slippage protections.

View File

@@ -17,10 +17,12 @@ This page outlines upcoming releases and expected changes.
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| **Name** | **Overview** | **Est Release Date** | **Status** | **Additional** |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Amaretto`_ | Protocol 4.1: Efficiency + Batch Fills | 03/15/21 | Development | |
| `Nifty`_ | ERC721 and ERC1155 support | 02/14/22 | Vote | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| *The following releases have been deployed* | | | | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Amaretto`_ | Protocol 4.1: Efficiency + Batch Fills | 03/15/21 | Deployed | |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Babooshka`_ | Connect Exchange Proxy to Staking | 02/08/21 | Deployed | `Release Notes <https://github.com/0xProject/0x-migrations/blob/main/src/exchange-proxy/migrations/log/9_babooshka.md>`__ |
+---------------------------------------------+---------------------------------------------------------------+----------------------+-------------+-------------------------------------------------------------------------------------------------------------------------------------+
| `Squire`_ | Aggregation for `V4 Orders <../basics/orders.html>`_ | 02/04/21 | Deployed | N/A |
@@ -45,6 +47,19 @@ This page outlines upcoming releases and expected changes.
Upcoming
========
Nifty
--------
- ERC721 and ERC1155 order types
- Batch fills for NFT orders
- Property based orders
- Ability to receive ETH in NFT orders
Past
=====
Amaretto
--------
@@ -53,10 +68,6 @@ Amaretto
- Mooniswap VIP
- Curve / Swerve VIP (via PLP Sandbox)
Past
=====
Babooshka
----------

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