Compare commits

..

154 Commits

Author SHA1 Message Date
Jacob Evans
5d603b2f80 Publish
- @0x/contracts-asset-proxy@3.1.3
 - @0x/contracts-broker@1.0.1
 - @0x/contracts-coordinator@3.0.6
 - @0x/contracts-dev-utils@1.0.6
 - @0x/contracts-erc1155@2.0.6
 - @0x/contracts-erc20-bridge-sampler@1.2.1
 - @0x/contracts-erc20@3.0.6
 - @0x/contracts-erc721@3.0.6
 - @0x/contracts-exchange-forwarder@4.1.0
 - @0x/contracts-exchange-libs@4.2.0
 - @0x/contracts-exchange@3.1.2
 - @0x/contracts-extensions@6.0.0
 - @0x/contracts-integrations@2.2.3
 - @0x/contracts-multisig@4.0.6
 - @0x/contracts-staking@2.0.6
 - @0x/contracts-test-utils@5.1.3
 - @0x/contracts-utils@4.2.1
 - 0x.js@9.0.7
 - @0x/abi-gen@5.1.2
 - @0x/assert@3.0.5
 - @0x/asset-swapper@4.1.1
 - @0x/base-contract@6.1.2
 - @0x/connect@6.0.5
 - @0x/contract-artifacts@3.4.1
 - @0x/contract-wrappers-test@12.2.7
 - @0x/contract-wrappers@13.4.2
 - @0x/contracts-gen@2.0.6
 - @0x/dev-utils@3.1.3
 - @0x/instant@1.0.44
 - @0x/json-schemas@5.0.5
 - @0x/migrations@6.0.2
 - @0x/monorepo-scripts@1.0.49
 - @0x/order-utils@10.1.3
 - @0x/orderbook@2.1.2
 - @0x/sol-compiler@4.0.6
 - @0x/sol-coverage@4.0.6
 - @0x/sol-doc@3.1.3
 - @0x/sol-profiler@4.0.6
 - @0x/sol-trace@3.0.6
 - @0x/sol-tracing-utils@7.0.6
 - @0x/sra-spec@3.0.5
 - @0x/subproviders@6.0.6
 - @0x/utils@5.3.0
 - @0x/web3-wrapper@7.0.5
2020-02-06 21:24:29 +10:00
Jacob Evans
0e1b08ff54 Updated CHANGELOGS & MD docs 2020-02-06 21:24:05 +10:00
David Sun
befc22d718 [FIX] asset-swapper liquidity breakdown (#2472)
* changed divided

* added changelog

* prettier

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-02-06 15:09:39 +10:00
Jacob Evans
4a62e80967 [asset-swapper] Bump sampler gas limit and allow for override (#2471)
* [asset-swapper] Bump sampler gas limit and allow for override

* Fix imports

* Set to 36e6
2020-02-06 12:31:28 +10:00
Jacob Evans
ee9ef9f2c1 [asset-swapper] prune before dummy order creation (#2470) 2020-02-06 07:08:31 +10:00
mzhu25
93dcb68437 Merge pull request #2455 from 0xProject/feature/broker/gods-unchained
`@0x/contracts-broker`: Property-based Gods Unchained orders
2020-02-04 10:53:54 -08:00
Michael Zhu
0691cc7909 rename _transferEthRefund -> _unwrapAndTransferEth 2020-02-04 10:13:07 -08:00
Michael Zhu
d82f34fe59 add weth-related integration tests 2020-02-04 10:13:07 -08:00
Michael Zhu
d2313b30af Address PR feedback and add support for affiliate fees 2020-02-04 10:13:07 -08:00
Michael Zhu
329719472a Move LibAssetDataTransfer and MixinWeth(Utils) to contracts-extensions 2020-02-04 10:13:02 -08:00
Michael Zhu
a2fcab47d4 skip coordinator client test 2020-02-04 10:08:25 -08:00
Michael Zhu
4ab5951c25 Add comments 2020-02-04 10:08:25 -08:00
Michael Zhu
403cabb201 more integrations tests 2020-02-04 10:08:25 -08:00
Michael Zhu
3da7c5d3e2 Move LibAssetDataTransfer from forwarder to exchange-libs package 2020-02-04 10:08:21 -08:00
Michael Zhu
c5e0de51aa Add Broker rich errors 2020-02-04 10:06:12 -08:00
Michael Zhu
c581f1bba4 Update Broker README 2020-02-04 10:06:12 -08:00
Michael Zhu
b8ac9c2edd lint 2020-02-04 10:06:10 -08:00
Michael Zhu
1027ee2481 Broker integrations tests 2020-02-04 10:05:17 -08:00
Michael Zhu
2f311f7821 GodsUnchainedValidator unit tests 2020-02-04 10:04:19 -08:00
Michael Zhu
a98c95b514 Broker contracts 2020-02-04 10:04:19 -08:00
Michael Zhu
5bbbae5b23 create contracts-broker package 2020-02-04 10:04:19 -08:00
Jacob Evans
f9c9b9f924 Prevent docs dir from being completely removed 2020-02-04 20:29:16 +10:00
Jacob Evans
5921208ea6 Publish
- @0x/contracts-asset-proxy@3.1.2
 - @0x/contracts-coordinator@3.0.5
 - @0x/contracts-dev-utils@1.0.5
 - @0x/contracts-erc1155@2.0.5
 - @0x/contracts-erc20-bridge-sampler@1.2.0
 - @0x/contracts-erc20@3.0.5
 - @0x/contracts-erc721@3.0.5
 - @0x/contracts-exchange-forwarder@4.0.5
 - @0x/contracts-exchange-libs@4.1.1
 - @0x/contracts-exchange@3.1.1
 - @0x/contracts-extensions@5.1.4
 - @0x/contracts-integrations@2.2.2
 - @0x/contracts-multisig@4.0.5
 - @0x/contracts-staking@2.0.5
 - @0x/contracts-test-utils@5.1.2
 - @0x/contracts-utils@4.2.0
 - 0x.js@9.0.6
 - @0x/abi-gen@5.1.1
 - @0x/asset-swapper@4.1.0
 - @0x/base-contract@6.1.1
 - @0x/contract-addresses@4.4.0
 - @0x/contract-wrappers-test@12.2.6
 - @0x/contract-wrappers@13.4.1
 - @0x/contracts-gen@2.0.5
 - @0x/dev-utils@3.1.2
 - @0x/instant@1.0.43
 - @0x/migrations@6.0.1
 - @0x/monorepo-scripts@1.0.48
 - @0x/order-utils@10.1.2
 - @0x/orderbook@2.1.1
 - @0x/sol-compiler@4.0.5
 - @0x/sol-coverage@4.0.5
 - @0x/sol-doc@3.1.2
 - @0x/sol-profiler@4.0.5
 - @0x/sol-trace@3.0.5
 - @0x/sol-tracing-utils@7.0.5
 - @0x/subproviders@6.0.5
2020-02-04 20:22:07 +10:00
Jacob Evans
f89c78abd1 Updated CHANGELOGS & MD docs 2020-02-04 20:21:45 +10:00
David Sun
74d3b9334c Add liquidity source breakdown to asset-swapper (#2465)
* add liquidity source breakdown to asset-swapper

* remove debug line

* use OptimizedMarketOrder metadata

* updated change-log

* prettier + lint

* bug fixes

* fixes

* Prettier

* Fix types

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-02-04 19:03:28 +10:00
Xianny
919fc66b9d Stop hardcoding contract addresses (#2461)
* stop hardcoding contract addresses

* update changelog

* export ContractAddresses for docs
2020-02-04 17:49:45 +10:00
Francesco Agosti
400fb5a5bb Merge pull request #2468 from 0xProject/feat/fix-test-publish
Bump maxBuffer?
2020-02-03 19:59:03 -08:00
fragosti
3bb4f9085c Add post-instal step 2020-02-03 18:13:31 -08:00
Jacob Evans
714c6cec3c Bump maxBuffer? 2020-02-03 17:50:32 -08:00
Lawrence Forman
cb69921202 ERC20BridgeSampler: Unlock full sampling on Kovan (#2459)
* `@0x/contracts-utils`: Update kovan addresses in `DeploymentConstants`

* `@0x/contracts-erc20-bridge-sampler`: Make source IDs static on all networks, not inherited from `DeploymentConstants`.

* `@0x/contract-addresses`: Update `ERC20BridgeSampler` addresses on mainnet and kovan.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-31 11:27:28 -05:00
Jacob Evans
277a0adac9 [base-contract] throw string revert error (#2453) 2020-01-24 07:48:26 +10:00
Jacob Evans
02d14f504f Remove docs from sol-doc gitignore 2020-01-23 12:10:42 +10:00
Jacob Evans
1ab7664a60 Publish
- @0x/contracts-integrations@2.2.1
 - 0x.js@9.0.5
 - @0x/asset-swapper@4.0.1
 - @0x/instant@1.0.42
2020-01-23 11:58:27 +10:00
Jacob Evans
1be46ffb7e Updated CHANGELOGS & MD docs 2020-01-23 11:58:10 +10:00
Lawrence Forman
6ca52aed0d @0x/asset-swapper: Fix understimated protocol fee in worst case quote. (#2452) 2020-01-22 18:22:56 -05:00
Jacob Evans
74e20970e2 Create docs folder for sol-doc 2020-01-22 18:56:10 +10:00
Jacob Evans
93f2b6b4d8 Publish
- @0x/contracts-asset-proxy@3.1.1
 - @0x/contracts-coordinator@3.0.4
 - @0x/contracts-dev-utils@1.0.4
 - @0x/contracts-erc1155@2.0.4
 - @0x/contracts-erc20-bridge-sampler@1.1.0
 - @0x/contracts-erc20@3.0.4
 - @0x/contracts-erc721@3.0.4
 - @0x/contracts-exchange-forwarder@4.0.4
 - @0x/contracts-exchange-libs@4.1.0
 - @0x/contracts-exchange@3.1.0
 - @0x/contracts-extensions@5.1.3
 - @0x/contracts-integrations@2.2.0
 - @0x/contracts-multisig@4.0.4
 - @0x/contracts-staking@2.0.4
 - @0x/contracts-test-utils@5.1.1
 - @0x/contracts-utils@4.1.0
 - 0x.js@9.0.4
 - @0x/abi-gen@5.1.0
 - @0x/assert@3.0.4
 - @0x/asset-swapper@4.0.0
 - @0x/base-contract@6.1.0
 - @0x/connect@6.0.4
 - @0x/contract-addresses@4.3.0
 - @0x/contract-artifacts@3.4.0
 - @0x/contract-wrappers-test@12.2.5
 - @0x/contract-wrappers@13.4.0
 - @0x/contracts-gen@2.0.4
 - @0x/dev-utils@3.1.1
 - @0x/instant@1.0.41
 - @0x/json-schemas@5.0.4
 - @0x/migrations@6.0.0
 - @0x/monorepo-scripts@1.0.47
 - @0x/order-utils@10.1.1
 - @0x/orderbook@2.1.0
 - @0x/sol-compiler@4.0.4
 - @0x/sol-coverage@4.0.4
 - @0x/sol-doc@3.1.1
 - @0x/sol-profiler@4.0.4
 - @0x/sol-trace@3.0.4
 - @0x/sol-tracing-utils@7.0.4
 - @0x/sra-spec@3.0.4
 - @0x/subproviders@6.0.4
 - @0x/utils@5.2.0
 - @0x/web3-wrapper@7.0.4
2020-01-22 18:49:46 +10:00
Jacob Evans
00e616b57a Updated CHANGELOGS & MD docs 2020-01-22 18:49:24 +10:00
Jacob Evans
e436673304 [asset-swapper] Change Exchange sell to marketSellOrdersFillOrKill (#2450)
* Change Exchange sell to marketSellOrdersFillOrKill

* Update Changelog
2020-01-22 18:25:09 +10:00
James Towle
ce04d3ce41 Fix regression in DevUtils (#2449)
* fix bug in OrderTransferSimulationUtils causing failures for 721 assets

* Patched the regression and added tests

* Added regression test for fillable order

* Created a test for in and out of process ganache

* Split up DevUtils into two contracts

* Updated migration

* Remove the in and out of process ganache test

* Fixed contract addresses

* Appease linter

* Addressed review comments and updated artifacts, wrappers, and snapshots

* Fixed regression after refactor

* Update DevUtils and libTransactionDecoder contracts on mainnet and testnets

* Addressed @mzhu's review feedback

* Addressed @hysz's review feedback

* Updated devUtils address on testnets and mainnet after deployment

Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>
Co-authored-by: Fabio B <kandinsky454@protonmail.ch>
2020-01-22 12:54:10 +10:00
Jacob Evans
4e46bf4697 Merge pull request #2427 from 0xProject/feature/erc20-bridge-sampler/query-multiple-buys-sells
ERC20BridgeSampler: Allow for batching multiple buy/sell samples
2020-01-22 11:54:45 +10:00
Jacob Evans
9b95508f99 Merge pull request #2445 from 0xProject/feat/asset-swapper/better-best-price-quote
asset-swapper: provide more accurate best quote price
2020-01-22 11:16:40 +10:00
Jacob Evans
c8c24456c1 Fix prettier 2020-01-22 10:01:18 +10:00
Lawrence Forman
80a6e82e1b @0x/contracts-erc20-bridge-sampler: Fix linter error. 2020-01-21 17:47:27 -05:00
Lawrence Forman
80cec20d38 Update packages/asset-swapper/src/utils/swap_quote_calculator.ts
Co-Authored-By: Jacob Evans <jacob@dekz.net>
2020-01-21 16:53:02 -05:00
Lawrence Forman
26cb22020d Update packages/asset-swapper/src/utils/swap_quote_calculator.ts
Co-Authored-By: Jacob Evans <jacob@dekz.net>
2020-01-21 16:52:54 -05:00
Lawrence Forman
09d05d09c9 @0x/asset-swapper: Provide more accurate best quote price. 2020-01-21 15:48:35 +10:00
Jacob Evans
160c91f908 Rename to Batch 2020-01-21 15:48:35 +10:00
Jacob Evans
58f41bcd42 Update asset-swapper WIP 2020-01-21 15:46:31 +10:00
Jacob Evans
0235429995 Update contract addresses 2020-01-21 09:15:47 +10:00
Lawrence Forman
f79697e117 @0x/contract-wrappers: Fix linter error. 2020-01-20 13:30:58 +10:00
Lawrence Forman
6f0019c71e @0x/contract-wrappers: Update IERC20BridgeSampler wrapper. 2020-01-20 13:30:58 +10:00
Lawrence Forman
1a04a18245 @0x/contract-artifacts: Update IERC20BridgeSampler artifact. 2020-01-20 13:30:57 +10:00
Lawrence Forman
0cf3ff8209 @0x/contracts-erc20-bridge-sampler: Increase gas forwarded to kyber and eth2dai.
`@0x/contracts-erc20-bridge-sampler`: Bail as soon as any quote from a DEX fails.

`@0x/contracts-erc20-bridge-sampler`: Fix broken tests.
2020-01-20 13:30:57 +10:00
Lawrence Forman
7f56091fbd @0x/asset-swapper: Add exponential sampling, exposed by sampleDistributionBase.
`@0x/asset-swapper`: Disable ethgasstation polling in tests.
`@0x/asset-swapper`: Tweak default hyper parameters to be friendlier to big fills.
2020-01-20 13:30:57 +10:00
F. Eugene Aumson
391f9b31f6 wrappers.py: satisfy linter (rm unnecessary pass) 2020-01-20 13:30:56 +10:00
F. Eugene Aumson
1d7c0f504a abi-gen: ran black on CLI test Python output 2020-01-20 13:30:56 +10:00
F. Eugene Aumson
9cdc62f918 abi-gen: fix bug w/ 2D arrays of UDT's in Python
Fix bug in handling 2-dimensional arrays of user defined data types in
generated Python code.
2020-01-20 13:30:56 +10:00
F. Eugene Aumson
6027d0481e wrappers.py: fix clean not rm'ing gen'd code 2020-01-20 13:30:55 +10:00
F. Eugene Aumson
277fb92f9e abi-gen: exit when black fails to parse Python
Note: this is not the same case as when the black executable can't be
found; that case is still just a (non-fatal) warning.
2020-01-20 13:30:55 +10:00
Jacob Evans
79b6c3c1af Update CHANGELOGs 2020-01-20 13:30:55 +10:00
Jacob Evans
ad17174119 Rename to Batch 2020-01-20 13:30:54 +10:00
Jacob Evans
6c2692eec0 Enable batch fetching from orderbook. Refactor 2020-01-20 13:30:54 +10:00
Jacob Evans
08640e8575 Update asset-swapper WIP 2020-01-20 13:30:54 +10:00
Jacob Evans
4a2575136f Allow for batching multiple buy/sell samples 2020-01-20 13:30:52 +10:00
Jacob Evans
e792afad17 Merge pull request #2441 from 0xProject/kroeger/fix_function_name_in_readme
Fixed function name in README, network -> chain
2020-01-20 13:29:45 +10:00
Jacob Evans
5ecc4b027d Merge pull request #2448 from 0xProject/fix/python-latest-ganache
Fix/python latest ganache
2020-01-20 13:25:26 +10:00
Jacob Evans
bc540f0cf0 [python] change gas estimate expected 2020-01-20 12:53:34 +10:00
Jacob Evans
a24b14c465 Pull 0xorg/ganache-cli:6.0.0 in circleci 2020-01-20 12:06:28 +10:00
Jacob Evans
c3f36c3123 Change python to use latest ganache 2020-01-20 11:50:43 +10:00
fabioberger
1d34da7557 Remove -v3-beta from snapshot name 2020-01-19 20:10:06 +01:00
fabioberger
27d74a4327 Update ganache-cli version to Istanbul-compatible version 2020-01-19 20:09:50 +01:00
mzhu25
8a20cc682c Merge pull request #2446 from 0xProject/feature/contract-addresses/update-dev-utils-1-17-20
`@0x/contract-addresses`: update DevUtils addresses
2020-01-17 13:38:04 -08:00
mzhu25
9b20359e7b Merge pull request #2431 from 0xProject/feature/fuzz/revert-assertions
`@0x/contracts-integrations`: Negative assertions for fuzzing
2020-01-17 13:10:00 -08:00
Michael Zhu
8866d0ccef update contract-addresses changelog 2020-01-17 12:42:56 -08:00
Michael Zhu
7fa91a9971 update dev-utils addresses 2020-01-17 12:39:07 -08:00
Amir Bandeali
28d1f3eef0 Merge pull request #2440 from 0xProject/feat/dev-utils/chai-bridge-validation
Add ChaiBridge order balance/allowance checks to DevUtils
2020-01-17 11:46:27 -08:00
Amir
f321cf6655 Update DevUtils contract wrapper 2020-01-17 11:08:04 -08:00
Amir
14ade737da Fix linting errors 2020-01-17 10:47:17 -08:00
Amir
41b1b1f141 Skip failing dydxBridge tests 2020-01-17 10:47:17 -08:00
Amir
25dfd47d32 Fix Ganache migrations 2020-01-17 10:47:17 -08:00
Amir
6afa9c8b92 Add mainnet integration tests for checking balances/allowances of ChaiBridge orders using DevUtils 2020-01-17 10:00:16 -08:00
Amir
2fc449da4c Fix integrations tests build 2020-01-17 10:00:16 -08:00
Amir
5dd3b8cf9d Special case unlimited allowance for Chai 2020-01-17 09:59:03 -08:00
Amir
e834fa0050 Split Dai calculation and erc20 balance checks into separate functions 2020-01-17 09:59:03 -08:00
Amir
9a97401606 Add ChaiBridge allowance checks 2020-01-17 09:59:03 -08:00
Amir
410a3fef18 Add ChaiBridge balance checks to DevUtils 2020-01-17 09:59:03 -08:00
Amir Bandeali
969b9814d5 Merge pull request #2442 from 0xProject/feat/forwarder/1155-support
Add 1155 support to Forwarder
2020-01-16 11:41:20 -08:00
Amir
2275e27b87 Rename internal functions in LibAssetDataTransfer and fix tests 2020-01-15 18:33:02 -08:00
Amir
62b06cd204 Add tests for transfering ERC1155 tokens out 2020-01-15 18:33:02 -08:00
Amir
350934ca21 Remove unused params 2020-01-15 18:32:57 -08:00
mzhu25
6332673434 Merge pull request #2436 from 0xProject/fix/dev-utils/map-fixes
`@0x/contracts-dev-utils`: LibAssetData fixes
2020-01-15 16:10:11 -08:00
Michael Zhu
f217840998 address comments 2020-01-15 13:22:53 -08:00
Michael Zhu
089ec35ceb update changelog 2020-01-15 13:22:53 -08:00
Michael Zhu
fecd0b809e tslint be trippin 2020-01-15 13:20:54 -08:00
Michael Zhu
4707a46561 Add negative assertions for endEpoch 2020-01-15 13:20:54 -08:00
Michael Zhu
616533c5a8 Add negative assertions for moveStake 2020-01-15 13:20:54 -08:00
Michael Zhu
c5b2991821 fix bug in finalizePool 2020-01-15 13:20:54 -08:00
Michael Zhu
c36d0fdc7c invalidWithdrawDelegatorRewardsAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
544e09cf4b invalidUnstakeAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
c110dc9e6a generic assertion for TRANSFER_FAILED reverts; _invalidStake generator 2020-01-15 13:20:54 -08:00
Michael Zhu
3bf37d6afd invalidDecreaseStakingPoolOperatorShareAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
b80ae5796b invalidCreateStakingPoolAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
2083632299 Update addresses, artifact, wrapper 2020-01-15 10:38:57 -08:00
Amir
3ca2f8ac9e Split out transfer logic into library, add 1155 support 2020-01-14 20:27:12 -08:00
Greg Hysz
7172432084 Merge pull request #2443 from 0xProject/fix/abiDecoder/LogDecodingDynamicData
Fixes log decoding of dynamic data
2020-01-14 18:33:57 -08:00
Greg Hysz
0e6afd147f Merge pull request #2437 from 0xProject/test/contracts-integrations/fuzzOrderMatching
Fuzz order matching
2020-01-14 18:04:27 -08:00
Greg Hysen
46275a4f43 Minor fixes to order matching fuzz code 2020-01-14 17:32:10 -08:00
Michael Zhu
1dca378e03 add division-by-zero check for ERC1155 too 2020-01-14 16:32:18 -08:00
Greg Hysen
06669594b1 Updated changelogs. 2020-01-14 16:18:50 -08:00
Greg Hysen
c09ac58ac0 Fuzz testing for matchOrders and matchOrdersWithMaximalFill. 2020-01-14 16:17:43 -08:00
Greg Hysen
e01d32ef1a added order matching functions to Taker actor. 2020-01-14 16:17:43 -08:00
Greg Hysen
5ea3bcf59e Added matchOrders and matchOrdersWithMaximalFill to the reference functions. 2020-01-14 16:17:43 -08:00
Greg Hysen
aa8b14b7ee Added order martching to Maker actor. Also fixed the joinStakingPool to record the pool id. 2020-01-14 16:17:43 -08:00
Greg Hysen
e1722cf739 Updated changelogs 2020-01-14 15:01:02 -08:00
Greg Hysen
7a7f70e15d Updating tests after fixing log decoding 2020-01-14 14:17:45 -08:00
Greg Hysen
b3c3ec16e5 Fixed log decoding. Dynamic structures were not decoding properly. Now uses AbiEncoder from utils package. 2020-01-14 14:17:42 -08:00
Michael Zhu
149f863951 unbreak migrations cli 2020-01-14 09:15:17 -08:00
Michael Zhu
684d09faac refactor LibAssetData tests 2020-01-13 15:29:37 -08:00
Michael Zhu
8a42691c80 Add test cases 2020-01-13 14:10:55 -08:00
Michael Zhu
d591b3dd98 LibAssetData fixes 2020-01-13 14:10:55 -08:00
Alex Kroeger
a90fb4d8b6 Fixed function name in README, network -> chain 2020-01-13 13:33:54 -08:00
Lawrence Forman
ebd08d9c63 Contract wrappers: Catch empty reverts on live networks (#2433)
* `@0x/utils`: Allow strict decoding of return values.

* `@0x/base-contract`: Catch empty call reverts on live networks.
`@0x/abi-gen`: Catch empty call reverts on live networks.

* `@0x/contracts-integrations`: Add mainnet contract wrapper `callAsync()` revert behavior tests.

* `@0x/contract-wrappers`: Regenerate wrappers to catch empty reverts on live networks.

* Update CHANGELOGs

* `@0x/contracts-integrations`: Fix solidity linter errors.

* `@0x/abi-gen`: Regenerate test outputs.

* `@0x/base-contract`: Update CHANGELOG.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-13 15:33:45 -05:00
Lawrence Forman
71731d223b Update contract wrappers (esp Forwarder + asset-swapper) (#2432)
* `@0x/contract-artifacts`: Update artifacts.

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

* `@0x/migrations`: Update Forwarder migration.

* `@0x/asset-swapper`: Update forwarder fees for new forwarder contract.

* `@0x/dev-utils`: Make `"istanbul"` the default `hardfork` when creating a ganache provider.

* `@0x/asset-swapper`: Remove debug code.

* `@0x/asset-swapper`: Remove `getSmartContractParamsOrThrowAsync()` because why does it even exist?
`@0x/asset-swapper`: Fix broken tests.
`@0x/asset-swapper`: Correctly handle affiliate fees in `getCalldataOrThrow()`.

* `@0x/contract-wrappers`: Export `ExchangeOwnershipTransferredEventArgs`.
`@0x/0x.js`: Export `ExchangeOwnershipTransferredEventArgs`.
`@0x/asset-swapper`: Unexport `MethodAbi`, `ConstructorStateMutability`, and `StateMutability`.

* Update changelogs

* Update packages/migrations/CHANGELOG.json

Co-Authored-By: Jacob Evans <jacob@dekz.net>

* Update packages/asset-swapper/CHANGELOG.json

Co-Authored-By: Jacob Evans <jacob@dekz.net>

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-01-09 15:35:22 -05:00
David Sun
726ea5e01e Merge pull request #2430 from 0xProject/feature/instant/enable-aggregator
Instant: whitelist tokens using bridge orders array
2020-01-08 16:50:40 -08:00
David Sun
16c7d2964b typo 2020-01-08 16:17:25 -08:00
David Sun
5a6e494bda lint + prettier 2020-01-08 16:16:29 -08:00
David Sun
88c6d89fbb whitelist constants array 2020-01-08 13:55:53 -08:00
Lawrence Forman
de12da18da Exchange signature validation fuzz tests (#2425)
* `@0x/contracts-integrations`: Add Exchange signature validation fuzz tests.

* `@0x/contracts-integrations`: Switch from actor pattern to just pure function generators.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-07 17:35:25 -05:00
Amir Bandeali
8d10736934 Merge pull request #2390 from 0xProject/feat/forwarder/v2-backwards-compatibility
Make Forwarder backwards compatible with v2
2020-01-07 13:04:27 -08:00
Amir
2328e02d82 Redeploy Forwarder 2020-01-07 11:03:18 -08:00
Michael Zhu
87cd5fca90 address comments 2020-01-07 11:03:18 -08:00
Michael Zhu
b70cb726c5 remove _noTakerFee (i.e. disallow StaticCall takerFeeAssetData) 2020-01-07 11:03:18 -08:00
Michael Zhu
295811ed5a add integrations tests 2020-01-07 11:03:18 -08:00
Michael Zhu
4bc55551c6 Add unit tests 2020-01-07 11:03:18 -08:00
Michael Zhu
2b8c6dc8f9 Forwarder StaticCall and MultiAsset buy support 2020-01-07 11:03:18 -08:00
Amir Bandeali
8b27380feb Fix dep version 2020-01-07 11:03:18 -08:00
Amir Bandeali
8de3a90851 Update CHANGELOG 2020-01-07 11:03:18 -08:00
Amir Bandeali
f8bb94d721 Remove unnecessary BigNumber cast 2020-01-06 22:12:05 -08:00
Amir Bandeali
0c6d06e7bb Redeploy bridges and Forwarder on mainnet 2020-01-06 22:12:05 -08:00
Amir Bandeali
b0aa5d3af2 Check makerFeeAssetData length before attempting to read id 2020-01-06 22:12:05 -08:00
Amir Bandeali
27d09713fd Add forwarder mainnet tests 2020-01-06 22:12:05 -08:00
Amir Bandeali
ff18852879 Fix build 2020-01-06 22:12:05 -08:00
Amir Bandeali
e515c91e5e Do not attempt to transfer asset if fill failed 2020-01-06 22:12:05 -08:00
Amir Bandeali
1d5800c4f7 Fix WETH compilation 2020-01-06 22:12:05 -08:00
Amir Bandeali
de8f190945 Change erc-20 package compiler target to istanbul 2020-01-06 22:12:05 -08:00
Amir Bandeali
f371e3c8d3 Regenerate boilerplate 2020-01-06 22:12:05 -08:00
Amir Bandeali
b15a6290a7 Handle v2 order edge cases 2020-01-06 22:12:05 -08:00
Amir Bandeali
0f151db355 Enable istanbul in Ganache 2020-01-06 22:12:05 -08:00
Amir Bandeali
fa99b75d1f Redeploy Forwarder and all bridges 2020-01-06 22:12:05 -08:00
Amir Bandeali
4a299c1f39 Change EVM target to istanbul for all contract packages except erc-20 2020-01-06 22:12:05 -08:00
Amir Bandeali
30a2015a68 Fix build 2020-01-06 22:12:05 -08:00
Amir Bandeali
c7c8a4891f Update TS boilerplate 2020-01-06 22:12:05 -08:00
Amir Bandeali
fe9fc6b459 Allow v2 orders to be filled if their makerAssetFeeData field uses a v2 order id 2020-01-06 22:12:05 -08:00
416 changed files with 14427 additions and 9145 deletions

View File

@@ -193,7 +193,7 @@ jobs:
working_directory: ~/repo working_directory: ~/repo
docker: docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8 - image: nikolaik/python-nodejs:python3.7-nodejs8
- image: 0xorg/ganache-cli - image: 0xorg/ganache-cli:6.0.0
- image: 0xorg/mesh:0xV3 - image: 0xorg/mesh:0xV3
environment: environment:
ETHEREUM_RPC_URL: 'http://localhost:8545' ETHEREUM_RPC_URL: 'http://localhost:8545'

5
.gitignore vendored
View File

@@ -79,6 +79,8 @@ TODO.md
.vscode .vscode
# generated contract artifacts/ # generated contract artifacts/
contracts/broker/generated-artifacts/
contracts/broker/test/generated-artifacts/
contracts/erc20-bridge-sampler/generated-artifacts/ contracts/erc20-bridge-sampler/generated-artifacts/
contracts/erc20-bridge-sampler/test/generated-artifacts/ contracts/erc20-bridge-sampler/test/generated-artifacts/
contracts/integrations/generated-artifacts/ contracts/integrations/generated-artifacts/
@@ -113,6 +115,7 @@ packages/sol-tracing-utils/test/fixtures/artifacts/
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/ python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
# generated truffle contract artifacts/ # generated truffle contract artifacts/
contracts/broker/build/
contracts/erc20-bridge-sampler/build/ contracts/erc20-bridge-sampler/build/
contracts/staking/build/ contracts/staking/build/
contracts/coordinator/build/ contracts/coordinator/build/
@@ -129,6 +132,8 @@ contracts/exchange-forwarder/build/
contracts/dev-utils/build/ contracts/dev-utils/build/
# generated contract wrappers # generated contract wrappers
contracts/broker/generated-wrappers/
contracts/broker/test/generated-wrappers/
packages/python-contract-wrappers/generated/ packages/python-contract-wrappers/generated/
contracts/erc20-bridge-sampler/generated-wrappers/ contracts/erc20-bridge-sampler/generated-wrappers/
contracts/erc20-bridge-sampler/test/generated-wrappers/ contracts/erc20-bridge-sampler/test/generated-wrappers/

View File

@@ -1,5 +1,9 @@
lib lib
.nyc_output .nyc_output
/contracts/broker/generated-wrappers
/contracts/broker/test/generated-wrappers
/contracts/broker/generated-artifacts
/contracts/broker/test/generated-artifacts
/contracts/integrations/generated-wrappers /contracts/integrations/generated-wrappers
/contracts/integrations/test/generated-wrappers /contracts/integrations/test/generated-wrappers
/contracts/integrations/generated-artifacts /contracts/integrations/generated-artifacts

View File

@@ -1,4 +1,31 @@
[ [
{
"timestamp": 1580988106,
"version": "3.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.1.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"version": "3.1.0", "version": "3.1.0",
"changes": [ "changes": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v3.1.3 - _February 6, 2020_
* Dependencies updated
## v3.1.2 - _February 4, 2020_
* Dependencies updated
## v3.1.1 - _January 22, 2020_
* Dependencies updated
## v3.1.0 - _January 6, 2020_ ## v3.1.0 - _January 6, 2020_
* Integration tests for DydxBridge with ERC20BridgeProxy. (#2401) * Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)

View File

@@ -4,7 +4,7 @@
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@@ -18,10 +18,22 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
contract PotLike {
function chi() external returns (uint256);
function rho() external returns (uint256);
function drip() external returns (uint256);
function join(uint256) external;
function exit(uint256) external;
}
// The actual Chai contract can be found here: https://github.com/dapphub/chai // The actual Chai contract can be found here: https://github.com/dapphub/chai
contract IChai { contract IChai is
IERC20Token
{
/// @dev Withdraws Dai owned by `src` /// @dev Withdraws Dai owned by `src`
/// @param src Address that owns Dai. /// @param src Address that owns Dai.
/// @param wad Amount of Dai to withdraw. /// @param wad Amount of Dai to withdraw.
@@ -30,4 +42,25 @@ contract IChai {
uint256 wad uint256 wad
) )
external; external;
/// @dev Queries Dai balance of Chai holder.
/// @param usr Address of Chai holder.
/// @return Dai balance.
function dai(address usr)
external
returns (uint256);
/// @dev Queries the Pot contract used by the Chai contract.
function pot()
external
returns (PotLike);
/// @dev Deposits Dai in exchange for Chai
/// @param dst Address to receive Chai.
/// @param wad Amount of Dai to deposit.
function join(
address dst,
uint256 wad
)
external;
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-asset-proxy", "name": "@0x/contracts-asset-proxy",
"version": "3.1.0", "version": "3.1.3",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -51,12 +51,12 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-gen": "^2.0.6",
"@0x/contracts-test-utils": "^5.1.0", "@0x/contracts-test-utils": "^5.1.3",
"@0x/contracts-utils": "^4.0.3", "@0x/contracts-utils": "^4.2.1",
"@0x/dev-utils": "^3.1.0", "@0x/dev-utils": "^3.1.3",
"@0x/sol-compiler": "^4.0.3", "@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22", "@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1", "@0x/types": "^3.1.1",
@@ -79,16 +79,16 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.0.3", "@0x/base-contract": "^6.1.2",
"@0x/contracts-dev-utils": "^1.0.3", "@0x/contracts-dev-utils": "^1.0.6",
"@0x/contracts-erc1155": "^2.0.3", "@0x/contracts-erc1155": "^2.0.6",
"@0x/contracts-erc20": "^3.0.3", "@0x/contracts-erc20": "^3.0.6",
"@0x/contracts-erc721": "^3.0.3", "@0x/contracts-erc721": "^3.0.6",
"@0x/contracts-exchange-libs": "^4.0.3", "@0x/contracts-exchange-libs": "^4.2.0",
"@0x/order-utils": "^10.1.0", "@0x/order-utils": "^10.1.3",
"@0x/typescript-typings": "^5.0.1", "@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2", "@0x/utils": "^5.3.0",
"@0x/web3-wrapper": "^7.0.3", "@0x/web3-wrapper": "^7.0.5",
"ethereum-types": "^3.0.0", "ethereum-types": "^3.0.0",
"lodash": "^4.17.11" "lodash": "^4.17.11"
}, },

View File

@@ -60,7 +60,7 @@ export class ERC1155ProxyWrapper {
txDefaults, txDefaults,
artifacts, artifacts,
); );
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress); const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
this._dummyTokenWrappers.push(erc1155Wrapper); this._dummyTokenWrappers.push(erc1155Wrapper);
} }
return this._dummyTokenWrappers; return this._dummyTokenWrappers;

View File

@@ -13,6 +13,9 @@ export {
StaticCallProxyContract, StaticCallProxyContract,
TestStaticCallTargetContract, TestStaticCallTargetContract,
UniswapBridgeContract, UniswapBridgeContract,
KyberBridgeContract,
ChaiBridgeContract,
IChaiContract,
} from './wrappers'; } from './wrappers';
export { ERC20Wrapper } from './erc20_wrapper'; export { ERC20Wrapper } from './erc20_wrapper';

View File

@@ -84,7 +84,7 @@ module.exports = {
solc: { solc: {
version: '0.5.9', version: '0.5.9',
settings: { settings: {
evmVersion: 'constantinople', evmVersion: 'istanbul',
optimizer: { optimizer: {
enabled: true, enabled: true,
runs: 1000000, runs: 1000000,

View File

@@ -0,0 +1,10 @@
# Blacklist all files
.*
*
# Whitelist lib
!lib/**/*
# Whitelist Solidity contracts
!contracts/src/**/*
# Blacklist tests in lib
/lib/test/*
# Package specific ignore

View File

@@ -0,0 +1,20 @@
[
{
"timestamp": 1580988106,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0",
"changes": [
{
"note": "Created package",
"pr": "2455"
}
]
}
]

View File

@@ -0,0 +1,14 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.1 - _February 6, 2020_
* Dependencies updated
## v1.0.0 - _Invalid date_
* Created package (#2455)

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,73 @@
## Broker
This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
## Installation
**Install**
```bash
npm install @0x/contracts-broker --save
```
## Bug bounty
A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0x/contracts-broker yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-broker yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -0,0 +1,26 @@
{
"artifactsDir": "./test/generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": false,
"isOfflineMode": false,
"compilerSettings": {
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 1000000,
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
},
"outputSelection": {
"*": {
"*": [
"abi",
"devdoc",
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
}
}
}

View File

@@ -0,0 +1,314 @@
/*
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.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./interfaces/IBroker.sol";
import "./interfaces/IPropertyValidator.sol";
import "./libs/LibBrokerRichErrors.sol";
// solhint-disable space-after-comma, var-name-mixedcase
contract Broker is
IBroker,
MixinWethUtils
{
// Contract addresses
// Address of the 0x Exchange contract
address internal EXCHANGE;
// Address of the 0x ERC1155 Asset Proxy contract
address internal ERC1155_PROXY;
// The following storage variables are used to cache data for the duration of the transcation.
// They should always cleared at the end of the transaction.
// Token IDs specified by the taker to be used to fill property-based orders.
uint256[] internal _cachedTokenIds;
// An index to the above array keeping track of which assets have been transferred.
uint256 internal _cacheIndex;
// The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to
// and from this address as the effectual taker of the orders.
address internal _sender;
using LibSafeMath for uint256;
using LibBytes for bytes;
using LibAssetDataTransfer for bytes;
/// @param exchange Address of the 0x Exchange contract.
/// @param exchange Address of the Wrapped Ether contract.
/// @param exchange Address of the 0x ERC1155 Asset Proxy contract.
constructor (
address exchange,
address weth
)
public
MixinWethUtils(
exchange,
weth
)
{
EXCHANGE = exchange;
ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
}
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
/// @param to This should be the maker of the order.
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata /* ids */,
uint256[] calldata amounts,
bytes calldata data
)
external
{
// Only the ERC1155 asset proxy contract should be calling this function.
if (msg.sender != ERC1155_PROXY) {
LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError(
msg.sender
));
}
// Only `takerAssetData` should be using Broker assets
if (from != address(this)) {
LibRichErrors.rrevert(
LibBrokerRichErrors.InvalidFromAddressError(from)
);
}
// Only one asset amount should be specified.
if (amounts.length != 1) {
LibRichErrors.rrevert(
LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length)
);
}
uint256 cacheIndex = _cacheIndex;
uint256 remainingAmount = amounts[0];
// Verify that there are enough broker assets to transfer
if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) {
LibRichErrors.rrevert(
LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length)
);
}
// Decode validator and params from `data`
(address tokenAddress, address validator, bytes memory propertyData) = abi.decode(
data,
(address, address, bytes)
);
while (remainingAmount != 0) {
uint256 tokenId = _cachedTokenIds[cacheIndex];
cacheIndex++;
// Validate asset properties
IPropertyValidator(validator).checkBrokerAsset(
tokenId,
propertyData
);
// Perform the transfer
IERC721Token(tokenAddress).transferFrom(
_sender,
to,
tokenId
);
remainingAmount--;
}
// Update cache index in storage
_cacheIndex = cacheIndex;
}
/// @dev Fills a single property-based order by the given amount using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param order The property-based order to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmount The amount to fill the order by.
/// @param signature The maker's signature of the given order.
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the maker and taker.
function brokerTrade(
uint256[] memory brokeredTokenIds,
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature,
bytes4 fillFunctionSelector,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (LibFillResults.FillResults memory fillResults)
{
// Cache the taker-supplied asset data
_cachedTokenIds = brokeredTokenIds;
// Cache the sender's address
_sender = msg.sender;
// Sanity-check the provided function selector
if (
fillFunctionSelector != IExchange(address(0)).fillOrder.selector &&
fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector
) {
LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector);
}
// Pay ETH affiliate fees to all feeRecipient addresses
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
// Perform the fill
bytes memory fillCalldata = abi.encodeWithSelector(
fillFunctionSelector,
order,
takerAssetFillAmount,
signature
);
// solhint-disable-next-line avoid-call-value
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata);
if (didSucceed) {
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
} else {
// Re-throw error
LibRichErrors.rrevert(returnData);
}
// Transfer maker asset to taker
if (!order.makerAssetData.equals(WETH_ASSET_DATA)) {
order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount);
}
// Refund remaining ETH to msg.sender.
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
_clearStorage();
return fillResults;
}
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param orders The property-based orders to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmounts The amounts to fill the orders by.
/// @param signatures The makers' signatures for the given orders.
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the makers and taker.
function batchBrokerTrade(
uint256[] memory brokeredTokenIds,
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
bytes[] memory signatures,
bytes4 batchFillFunctionSelector,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (LibFillResults.FillResults[] memory fillResults)
{
// Cache the taker-supplied asset data
_cachedTokenIds = brokeredTokenIds;
// Cache the sender's address
_sender = msg.sender;
// Sanity-check the provided function selector
if (
batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector &&
batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector &&
batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector
) {
LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector);
}
// Pay ETH affiliate fees to all feeRecipient addresses
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
// Perform the batch fill
bytes memory batchFillCalldata = abi.encodeWithSelector(
batchFillFunctionSelector,
orders,
takerAssetFillAmounts,
signatures
);
// solhint-disable-next-line avoid-call-value
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata);
if (didSucceed) {
// solhint-disable-next-line indent
fillResults = abi.decode(returnData, (LibFillResults.FillResults[]));
} else {
// Re-throw error
LibRichErrors.rrevert(returnData);
}
// Transfer maker assets to taker
for (uint256 i = 0; i < orders.length; i++) {
if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) {
orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount);
}
}
// Refund remaining ETH to msg.sender.
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
_clearStorage();
return fillResults;
}
function _clearStorage()
private
{
delete _cachedTokenIds;
_cacheIndex = 0;
_sender = address(0);
}
}

View File

@@ -0,0 +1,101 @@
/*
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.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
// solhint-disable space-after-comma
interface IBroker {
/// @dev Fills a single property-based order by the given amount using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param order The property-based order to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmount The amount to fill the order by.
/// @param signature The maker's signature of the given order.
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the maker and taker.
function brokerTrade(
uint256[] calldata brokeredTokenIds,
LibOrder.Order calldata order,
uint256 takerAssetFillAmount,
bytes calldata signature,
bytes4 fillFunctionSelector,
uint256[] calldata ethFeeAmounts,
address payable[] calldata feeRecipients
)
external
payable
returns (LibFillResults.FillResults memory fillResults);
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param orders The property-based orders to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmounts The amounts to fill the orders by.
/// @param signatures The makers' signatures for the given orders.
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the makers and taker.
function batchBrokerTrade(
uint256[] calldata brokeredTokenIds,
LibOrder.Order[] calldata orders,
uint256[] calldata takerAssetFillAmounts,
bytes[] calldata signatures,
bytes4 batchFillFunctionSelector,
uint256[] calldata ethFeeAmounts,
address payable[] calldata feeRecipients
)
external
payable
returns (LibFillResults.FillResults[] memory fillResults);
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
/// @param to This should be the maker of the order.
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata /* ids */,
uint256[] calldata amounts,
bytes calldata data
)
external;
}

View File

@@ -19,20 +19,15 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./libs/LibConstants.sol";
import "./MixinMatchOrders.sol";
import "./MixinAssets.sol";
interface IGodsUnchained {
// solhint-disable no-empty-blocks /// @dev Returns the proto and quality for a particular card given its token id
contract OrderMatcher is /// @param tokenId The id of the card to query.
MixinMatchOrders, /// @return proto The proto of the given card.
MixinAssets /// @return quality The quality of the given card
{ function getDetails(uint256 tokenId)
constructor (address _exchange) external
public view
LibConstants(_exchange) returns (uint16 proto, uint8 quality);
Ownable()
{}
} }

View File

@@ -17,15 +17,19 @@
*/ */
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
contract IThresholdAsset { interface IPropertyValidator {
/// @param _owner The address from which the balance will be retrieved /// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`.
/// @return Balance of owner /// Should revert if the asset does not satisfy the specified properties.
function balanceOf(address _owner) /// @param tokenId The ERC721 tokenId of the asset to check.
/// @param propertyData Encoded properties or auxiliary data needed to perform the check.
function checkBrokerAsset(
uint256 tokenId,
bytes calldata propertyData
)
external external
view view;
returns (uint256);
} }

View File

@@ -0,0 +1,109 @@
/*
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.5.9;
library LibBrokerRichErrors {
// bytes4(keccak256("InvalidFromAddressError(address)"))
bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR =
0x906bfb3c;
// bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)"))
bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR =
0xba9be200;
// bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)"))
bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR =
0x55272586;
// bytes4(keccak256("InvalidFunctionSelectorError(bytes4)"))
bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR =
0x540943f1;
// bytes4(keccak256("OnlyERC1155ProxyError(address)"))
bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR =
0xccc529af;
// solhint-disable func-name-mixedcase
function InvalidFromAddressError(
address from
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INVALID_FROM_ADDRESS_ERROR_SELECTOR,
from
);
}
function AmountsLengthMustEqualOneError(
uint256 amountsLength
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR,
amountsLength
);
}
function TooFewBrokerAssetsProvidedError(
uint256 numBrokeredAssets
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR,
numBrokeredAssets
);
}
function InvalidFunctionSelectorError(
bytes4 selector
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR,
selector
);
}
function OnlyERC1155ProxyError(
address sender
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ONLY_ERC_1155_PROXY_ERROR_SELECTOR,
sender
);
}
}

View File

@@ -0,0 +1,61 @@
/*
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.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "../interfaces/IGodsUnchained.sol";
import "../interfaces/IPropertyValidator.sol";
contract GodsUnchainedValidator is
IPropertyValidator
{
IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase
using LibBytes for bytes;
constructor(address _godsUnchained)
public
{
GODS_UNCHAINED = IGodsUnchained(_godsUnchained);
}
/// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`.
/// Reverts if the card doesn't match the specified proto and quality.
/// @param tokenId The ERC721 tokenId of the card to check.
/// @param propertyData Encoded proto and quality that the card is expected to have.
function checkBrokerAsset(
uint256 tokenId,
bytes calldata propertyData
)
external
view
{
(uint16 expectedProto, uint8 expectedQuality) = abi.decode(
propertyData,
(uint16, uint8)
);
// Validate card properties.
(uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId);
require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH");
require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH");
}
}

View File

@@ -0,0 +1,55 @@
/*
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.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc721/contracts/test/DummyERC721Token.sol";
import "../src/interfaces/IGodsUnchained.sol";
contract TestGodsUnchained is
IGodsUnchained,
DummyERC721Token
{
mapping (uint256 => uint16) internal _protoByTokenId;
mapping (uint256 => uint8) internal _qualityByTokenId;
constructor (
string memory _name,
string memory _symbol
)
public
DummyERC721Token(_name, _symbol)
{} // solhint-disable-line no-empty-blocks
function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality)
external
{
_protoByTokenId[tokenId] = proto;
_qualityByTokenId[tokenId] = quality;
}
function getDetails(uint256 tokenId)
external
view
returns (uint16 proto, uint8 quality)
{
return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]);
}
}

View File

@@ -0,0 +1,96 @@
{
"name": "@0x/contracts-broker",
"version": "1.0.1",
"engines": {
"node": ">=6.12"
},
"description": "Extension of 0x protocol for property-based orders",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn build:contracts && yarn build:ts",
"build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"build:ts": "tsc -b",
"build:ci": "yarn build",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
"compile:truffle": "truffle compile",
"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"
},
"config": {
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.1.2",
"@0x/contracts-asset-proxy": "^3.1.3",
"@0x/contracts-erc20": "^3.0.6",
"@0x/contracts-erc721": "^3.0.6",
"@0x/contracts-exchange": "^3.1.2",
"@0x/contracts-exchange-libs": "^4.2.0",
"@0x/contracts-gen": "^2.0.6",
"@0x/contracts-test-utils": "^5.1.3",
"@0x/contracts-utils": "^4.2.1",
"@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1",
"@0x/web3-wrapper": "^7.0.5",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"lodash": "^4.17.11",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "^0.15.0",
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.1.2",
"@0x/order-utils": "^10.1.3",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.3.0",
"ethereum-types": "^3.0.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -0,0 +1,23 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as Broker from '../generated-artifacts/Broker.json';
import * as GodsUnchainedValidator from '../generated-artifacts/GodsUnchainedValidator.json';
import * as IBroker from '../generated-artifacts/IBroker.json';
import * as IGodsUnchained from '../generated-artifacts/IGodsUnchained.json';
import * as IPropertyValidator from '../generated-artifacts/IPropertyValidator.json';
import * as LibBrokerRichErrors from '../generated-artifacts/LibBrokerRichErrors.json';
import * as TestGodsUnchained from '../generated-artifacts/TestGodsUnchained.json';
export const artifacts = {
Broker: Broker as ContractArtifact,
IBroker: IBroker as ContractArtifact,
IGodsUnchained: IGodsUnchained as ContractArtifact,
IPropertyValidator: IPropertyValidator as ContractArtifact,
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
};

View File

@@ -0,0 +1,42 @@
import { assetDataUtils } from '@0x/order-utils';
import { AbiEncoder, BigNumber } from '@0x/utils';
export const godsUnchainedUtils = {
/**
* Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator.
*/
encodePropertyData(proto: BigNumber, quality: BigNumber): string {
return AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]).encode({
proto,
quality,
});
},
/**
* Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData
* of a property-based GodsUnchained order. Must also provide the addresses of the Broker,
* GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies
* how many cards are expected for each "unit" of the takerAssetAmount. For example, If the
* takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards
* with the given proto and quality to fill the order. If an odd number is provided, the fill fails.
*/
encodeBrokerAssetData(
brokerAddress: string,
godsUnchainedAddress: string,
validatorAddress: string,
proto: BigNumber,
quality: BigNumber,
bundleSize: number = 1,
): string {
const dataEncoder = AbiEncoder.create([
{ name: 'godsUnchainedAddress', type: 'address' },
{ name: 'validatorAddress', type: 'address' },
{ name: 'propertyData', type: 'bytes' },
]);
const propertyData = AbiEncoder.create([
{ name: 'proto', type: 'uint16' },
{ name: 'quality', type: 'uint8' },
]).encode({ proto, quality });
const data = dataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData });
return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], data);
},
};

View File

@@ -0,0 +1,32 @@
export { artifacts } from './artifacts';
export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
export { godsUnchainedUtils } from './gods_unchained_utils';
export { BrokerRevertErrors } from '@0x/utils';
export {
ContractArtifact,
ContractChains,
CompilerOpts,
StandardContractOutput,
CompilerSettings,
ContractChainData,
ContractAbi,
DevdocOutput,
EvmOutput,
CompilerSettingsMetadata,
OptimizerSettings,
OutputField,
ParamDescription,
EvmBytecodeOutput,
AbiDefinition,
FunctionAbi,
EventAbi,
RevertErrorAbi,
EventParameter,
DataItem,
MethodAbi,
ConstructorAbi,
FallbackAbi,
ConstructorStateMutability,
TupleDataItem,
StateMutability,
} from 'ethereum-types';

View File

@@ -0,0 +1,12 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/broker';
export * from '../generated-wrappers/gods_unchained_validator';
export * from '../generated-wrappers/i_broker';
export * from '../generated-wrappers/i_gods_unchained';
export * from '../generated-wrappers/i_property_validator';
export * from '../generated-wrappers/lib_broker_rich_errors';
export * from '../generated-wrappers/test_gods_unchained';

View File

@@ -0,0 +1,23 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as Broker from '../test/generated-artifacts/Broker.json';
import * as GodsUnchainedValidator from '../test/generated-artifacts/GodsUnchainedValidator.json';
import * as IBroker from '../test/generated-artifacts/IBroker.json';
import * as IGodsUnchained from '../test/generated-artifacts/IGodsUnchained.json';
import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json';
import * as LibBrokerRichErrors from '../test/generated-artifacts/LibBrokerRichErrors.json';
import * as TestGodsUnchained from '../test/generated-artifacts/TestGodsUnchained.json';
export const artifacts = {
Broker: Broker as ContractArtifact,
IBroker: IBroker as ContractArtifact,
IGodsUnchained: IGodsUnchained as ContractArtifact,
IPropertyValidator: IPropertyValidator as ContractArtifact,
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
};

View File

@@ -0,0 +1,56 @@
import { blockchainTests, constants, expect, getRandomInteger } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { godsUnchainedUtils } from '../src/gods_unchained_utils';
import { artifacts } from './artifacts';
import { GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
blockchainTests.resets('GodsUnchainedValidator unit tests', env => {
let godsUnchained: TestGodsUnchainedContract;
let validator: GodsUnchainedValidatorContract;
before(async () => {
godsUnchained = await TestGodsUnchainedContract.deployFrom0xArtifactAsync(
artifacts.TestGodsUnchained,
env.provider,
env.txDefaults,
artifacts,
'Gods Unchained Cards',
'GU',
);
validator = await GodsUnchainedValidatorContract.deployFrom0xArtifactAsync(
artifacts.GodsUnchainedValidator,
env.provider,
env.txDefaults,
artifacts,
godsUnchained.address,
);
});
describe('checkBrokerAsset', () => {
const proto = new BigNumber(42);
const quality = new BigNumber(7);
const propertyData = godsUnchainedUtils.encodePropertyData(proto, quality);
it('succeeds if assetData proto and quality match propertyData', async () => {
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
await godsUnchained.setTokenProperties(tokenId, proto, quality).awaitTransactionSuccessAsync();
await validator.checkBrokerAsset(tokenId, propertyData).callAsync();
});
it("reverts if assetData proto doesn't match propertyData", async () => {
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync();
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
expect(tx).to.revertWith('PROTO_MISMATCH');
});
it("reverts if assetData quality doesn't match proeprtyData", async () => {
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync();
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
expect(tx).to.revertWith('QUALITY_MISMATCH');
});
});
});

View File

@@ -0,0 +1,12 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/broker';
export * from '../test/generated-wrappers/gods_unchained_validator';
export * from '../test/generated-wrappers/i_broker';
export * from '../test/generated-wrappers/i_gods_unchained';
export * from '../test/generated-wrappers/i_property_validator';
export * from '../test/generated-wrappers/lib_broker_rich_errors';
export * from '../test/generated-wrappers/test_gods_unchained';

View File

@@ -0,0 +1,96 @@
/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* truffleframework.com/docs/advanced/configuration
*
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/
// const HDWalletProvider = require('truffle-hdwallet-provider');
// const infuraKey = "fj4jll3k.....";
//
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
// development: {
// host: "127.0.0.1", // Localhost (default: none)
// port: 8545, // Standard Ethereum port (default: none)
// network_id: "*", // Any network (default: none)
// },
// Another network with more advanced options...
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send txs from (default: accounts[0])
// websockets: true // Enable EventEmitter interface for web3 (default: false)
// },
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
// ropsten: {
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
// network_id: 3, // Ropsten's id
// gas: 5500000, // Ropsten has a lower block limit than mainnet
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
// },
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: '0.5.9',
settings: {
evmVersion: 'istanbul',
optimizer: {
enabled: true,
runs: 1000000,
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
},
},
},
},
};

View File

@@ -0,0 +1,22 @@
{
"extends": "../../tsconfig",
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/Broker.json",
"generated-artifacts/GodsUnchainedValidator.json",
"generated-artifacts/IBroker.json",
"generated-artifacts/IGodsUnchained.json",
"generated-artifacts/IPropertyValidator.json",
"generated-artifacts/LibBrokerRichErrors.json",
"generated-artifacts/TestGodsUnchained.json",
"test/generated-artifacts/Broker.json",
"test/generated-artifacts/GodsUnchainedValidator.json",
"test/generated-artifacts/IBroker.json",
"test/generated-artifacts/IGodsUnchained.json",
"test/generated-artifacts/IPropertyValidator.json",
"test/generated-artifacts/LibBrokerRichErrors.json",
"test/generated-artifacts/TestGodsUnchained.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@@ -0,0 +1,6 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@@ -0,0 +1,7 @@
{
"extends": "../../typedoc-tsconfig",
"compilerOptions": {
"outDir": "lib"
},
"include": ["./src/**/*", "./test/**/*"]
}

View File

@@ -1,4 +1,31 @@
[ [
{
"timestamp": 1580988106,
"version": "3.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1578272714, "timestamp": 1578272714,
"version": "3.0.3", "version": "3.0.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v3.0.6 - _February 6, 2020_
* Dependencies updated
## v3.0.5 - _February 4, 2020_
* Dependencies updated
## v3.0.4 - _January 22, 2020_
* Dependencies updated
## v3.0.3 - _January 6, 2020_ ## v3.0.3 - _January 6, 2020_
* Dependencies updated * Dependencies updated

View File

@@ -3,7 +3,7 @@
"contractsDir": "./contracts", "contractsDir": "./contracts",
"useDockerisedSolc": false, "useDockerisedSolc": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-coordinator", "name": "@0x/contracts-coordinator",
"version": "3.0.3", "version": "3.0.6",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -52,19 +52,19 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/contracts-asset-proxy": "^3.1.0", "@0x/contracts-asset-proxy": "^3.1.3",
"@0x/contracts-dev-utils": "^1.0.3", "@0x/contracts-dev-utils": "^1.0.6",
"@0x/contracts-erc20": "^3.0.3", "@0x/contracts-erc20": "^3.0.6",
"@0x/contracts-exchange": "^3.0.3", "@0x/contracts-exchange": "^3.1.2",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-gen": "^2.0.6",
"@0x/contracts-test-utils": "^5.1.0", "@0x/contracts-test-utils": "^5.1.3",
"@0x/dev-utils": "^3.1.0", "@0x/dev-utils": "^3.1.3",
"@0x/order-utils": "^10.1.0", "@0x/order-utils": "^10.1.3",
"@0x/sol-compiler": "^4.0.3", "@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22", "@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@0x/web3-wrapper": "^7.0.3", "@0x/web3-wrapper": "^7.0.5",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
"@types/node": "*", "@types/node": "*",
@@ -84,14 +84,14 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/assert": "^3.0.3", "@0x/assert": "^3.0.5",
"@0x/base-contract": "^6.0.3", "@0x/base-contract": "^6.1.2",
"@0x/contract-addresses": "^4.2.0", "@0x/contract-addresses": "^4.4.0",
"@0x/contracts-utils": "^4.0.3", "@0x/contracts-utils": "^4.2.1",
"@0x/json-schemas": "^5.0.3", "@0x/json-schemas": "^5.0.5",
"@0x/types": "^3.1.1", "@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1", "@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2", "@0x/utils": "^5.3.0",
"ethereum-types": "^3.0.0", "ethereum-types": "^3.0.0",
"http-status-codes": "^1.3.2" "http-status-codes": "^1.3.2"
}, },

View File

@@ -84,7 +84,7 @@ module.exports = {
solc: { solc: {
version: '0.5.9', version: '0.5.9',
settings: { settings: {
evmVersion: 'constantinople', evmVersion: 'istanbul',
optimizer: { optimizer: {
enabled: true, enabled: true,
runs: 1000000, runs: 1000000,

View File

@@ -1,4 +1,31 @@
[ [
{
"timestamp": 1580988106,
"version": "1.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "1.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"version": "1.0.3", "version": "1.0.3",
"changes": [ "changes": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v1.0.6 - _February 6, 2020_
* Dependencies updated
## v1.0.5 - _February 4, 2020_
* Dependencies updated
## v1.0.4 - _January 22, 2020_
* Dependencies updated
## v1.0.3 - _January 6, 2020_ ## v1.0.3 - _January 6, 2020_
* Fixed ERC721 duplicate token ID bug (#2400) * Fixed ERC721 duplicate token ID bug (#2400)

View File

@@ -41,13 +41,13 @@ yarn install
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash ```bash
PKG=@0x/contracts-extensions yarn build PKG=@0x/contracts-dev-utils yarn build
``` ```
Or continuously rebuild on change: Or continuously rebuild on change:
```bash ```bash
PKG=@0x/contracts-extensions yarn watch PKG=@0x/contracts-dev-utils yarn watch
``` ```
### Clean ### Clean

View File

@@ -4,10 +4,10 @@
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 200, "runs": 5000,
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
}, },
"outputSelection": { "outputSelection": {

View File

@@ -26,25 +26,33 @@ import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "./OrderValidationUtils.sol"; import "./OrderValidationUtils.sol";
import "./OrderTransferSimulationUtils.sol"; import "./OrderTransferSimulationUtils.sol";
import "./LibTransactionDecoder.sol";
import "./EthBalanceChecker.sol"; import "./EthBalanceChecker.sol";
// solhint-disable no-empty-blocks // solhint-disable no-empty-blocks
contract DevUtils is contract DevUtils is
OrderValidationUtils, OrderValidationUtils,
LibTransactionDecoder,
LibEIP712ExchangeDomain, LibEIP712ExchangeDomain,
EthBalanceChecker EthBalanceChecker
{ {
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
OrderValidationUtils(_exchange) OrderValidationUtils(
_exchange,
_chaiBridge
)
OrderTransferSimulationUtils(_exchange) OrderTransferSimulationUtils(_exchange)
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
{} {}
function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange) function getOrderHash(
LibOrder.Order memory order,
uint256 chainId,
address exchange
)
public public
pure pure
returns (bytes32 orderHash) returns (bytes32 orderHash)

View File

@@ -26,10 +26,14 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
contract LibAssetData { contract LibAssetData is
DeploymentConstants
{
// 2^256 - 1 // 2^256 - 1
uint256 constant internal _MAX_UINT256 = uint256(-1); uint256 constant internal _MAX_UINT256 = uint256(-1);
@@ -41,9 +45,13 @@ contract LibAssetData {
address internal _ERC721_PROXY_ADDRESS; address internal _ERC721_PROXY_ADDRESS;
address internal _ERC1155_PROXY_ADDRESS; address internal _ERC1155_PROXY_ADDRESS;
address internal _STATIC_CALL_PROXY_ADDRESS; address internal _STATIC_CALL_PROXY_ADDRESS;
address internal _CHAI_BRIDGE_ADDRESS;
// solhint-enable var-name-mixedcase // solhint-enable var-name-mixedcase
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
{ {
_EXCHANGE = IExchange(_exchange); _EXCHANGE = IExchange(_exchange);
@@ -51,6 +59,7 @@ contract LibAssetData {
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector); _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector); _STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
_CHAI_BRIDGE_ADDRESS = _chaiBridge;
} }
/// @dev Returns the owner's balance of the assets(s) specified in /// @dev Returns the owner's balance of the assets(s) specified in
@@ -62,7 +71,6 @@ contract LibAssetData {
/// @return Number of assets (or asset baskets) held by owner. /// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData) function getBalance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 balance) returns (uint256 balance)
{ {
// Get id of AssetProxy contract // Get id of AssetProxy contract
@@ -71,16 +79,8 @@ contract LibAssetData {
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address // Get ERC20 token address
address tokenAddress = assetData.readAddress(16); address tokenAddress = assetData.readAddress(16);
balance = _erc20BalanceOf(tokenAddress, ownerAddress);
// Encode data for `balanceOf(ownerAddress)`
bytes memory balanceOfData = abi.encodeWithSelector(
IERC20Token(address(0)).balanceOf.selector,
ownerAddress
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id // Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
@@ -94,12 +94,18 @@ contract LibAssetData {
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata); (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0); address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
balance = currentOwnerAddress == ownerAddress ? 1 : 0; balance = currentOwnerAddress == ownerAddress ? 1 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address, array of ids, and array of values // Get ERC1155 token address, array of ids, and array of values
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData); (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
uint256 length = tokenIds.length; uint256 length = tokenIds.length;
for (uint256 i = 0; i != length; i++) { for (uint256 i = 0; i != length; i++) {
// Skip over the token if the corresponding value is 0.
if (tokenValues[i] == 0) {
continue;
}
// Encode data for `balanceOf(ownerAddress, tokenIds[i]) // Encode data for `balanceOf(ownerAddress, tokenIds[i])
bytes memory balanceOfData = abi.encodeWithSelector( bytes memory balanceOfData = abi.encodeWithSelector(
IERC1155(address(0)).balanceOf.selector, IERC1155(address(0)).balanceOf.selector,
@@ -113,10 +119,14 @@ contract LibAssetData {
// Scale total balance down by corresponding value in assetData // Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / tokenValues[i]; uint256 scaledBalance = totalBalance / tokenValues[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) { if (scaledBalance < balance || balance == 0) {
balance = scaledBalance; balance = scaledBalance;
} }
} }
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// Encode data for `staticCallProxy.transferFrom(assetData,...)` // Encode data for `staticCallProxy.transferFrom(assetData,...)`
bytes memory transferFromData = abi.encodeWithSelector( bytes memory transferFromData = abi.encodeWithSelector(
@@ -132,17 +142,36 @@ contract LibAssetData {
// Success means that the staticcall can be made an unlimited amount of times // Success means that the staticcall can be made an unlimited amount of times
balance = success ? _MAX_UINT256 : 0; balance = success ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
uint256 chaiBalance = _erc20BalanceOf(_getChaiAddress(), ownerAddress);
// Calculate Dai balance
balance = _convertChaiToDaiAmount(chaiBalance);
}
// Balance will be 0 if bridge is not supported
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas // Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData); (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length; uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) { for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (assetAmounts[i] == 0) {
continue;
}
// Query balance of individual assetData // Query balance of individual assetData
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]); uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
// Scale total balance down by corresponding value in assetData // Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / assetAmounts[i]; uint256 scaledBalance = totalBalance / assetAmounts[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) { if (scaledBalance < balance || balance == 0) {
balance = scaledBalance; balance = scaledBalance;
} }
@@ -160,7 +189,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input. /// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData) function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory balances) returns (uint256[] memory balances)
{ {
uint256 length = assetData.length; uint256 length = assetData.length;
@@ -181,7 +209,6 @@ contract LibAssetData {
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. /// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData) function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 allowance) returns (uint256 allowance)
{ {
// Get id of AssetProxy contract // Get id of AssetProxy contract
@@ -193,11 +220,19 @@ contract LibAssetData {
uint256 length = nestedAssetData.length; uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) { for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (amounts[i] == 0) {
continue;
}
// Query allowance of individual assetData // Query allowance of individual assetData
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]); uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
// Scale total allowance down by corresponding value in assetData // Scale total allowance down by corresponding value in assetData
uint256 scaledAllowance = totalAllowance / amounts[i]; uint256 scaledAllowance = totalAllowance / amounts[i];
if (scaledAllowance == 0) {
return 0;
}
if (scaledAllowance < allowance || allowance == 0) { if (scaledAllowance < allowance || allowance == 0) {
allowance = scaledAllowance; allowance = scaledAllowance;
} }
@@ -219,6 +254,7 @@ contract LibAssetData {
// Query allowance // Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData); (bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id // Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
@@ -244,6 +280,7 @@ contract LibAssetData {
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true // Allowance is 2^256 - 1 if `isApprovedForAll` returned true
allowance = _MAX_UINT256; allowance = _MAX_UINT256;
} }
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address // Get ERC1155 token address
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData); (, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
@@ -258,9 +295,26 @@ contract LibAssetData {
// Query allowance // Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0; allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// The StaticCallProxy does not require any approvals // The StaticCallProxy does not require any approvals
allowance = _MAX_UINT256; allowance = _MAX_UINT256;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
bytes memory allowanceData = abi.encodeWithSelector(
IERC20Token(address(0)).allowance.selector,
ownerAddress,
_CHAI_BRIDGE_ADDRESS
);
(bool success, bytes memory returnData) = _getChaiAddress().staticcall(allowanceData);
uint256 chaiAllowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
// Dai allowance is unlimited if Chai allowance is unlimited
allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance);
}
// Allowance will be 0 if bridge is not supported
} }
// Allowance will be 0 if the assetProxyId is unknown // Allowance will be 0 if the assetProxyId is unknown
@@ -274,7 +328,6 @@ contract LibAssetData {
/// element corresponding to the same-indexed element in the assetData input. /// element corresponding to the same-indexed element in the assetData input.
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory allowances) returns (uint256[] memory allowances)
{ {
uint256 length = assetData.length; uint256 length = assetData.length;
@@ -292,7 +345,6 @@ contract LibAssetData {
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData) function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 balance, uint256 allowance) returns (uint256 balance, uint256 allowance)
{ {
balance = getBalance(ownerAddress, assetData); balance = getBalance(ownerAddress, assetData);
@@ -308,7 +360,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input. /// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory balances, uint256[] memory allowances) returns (uint256[] memory balances, uint256[] memory allowances)
{ {
balances = getBatchBalances(ownerAddress, assetData); balances = getBatchBalances(ownerAddress, assetData);
@@ -589,6 +640,35 @@ contract LibAssetData {
); );
} }
/// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset
/// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address
/// of the bridge contract, and extra data to be passed to the bridge contract.
function decodeERC20BridgeAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
)
{
assetProxyId = assetData.readBytes4(0);
require(
assetProxyId == IAssetData(address(0)).ERC20Bridge.selector,
"WRONG_PROXY_ID"
);
(tokenAddress, bridgeAddress, bridgeData) = abi.decode(
assetData.slice(4, assetData.length),
(address, address, bytes)
);
}
/// @dev Reverts if assetData is not of a valid format for its given proxy id.
/// @param assetData AssetProxy compliant asset data.
function revertIfInvalidAssetData(bytes memory assetData) function revertIfInvalidAssetData(bytes memory assetData)
public public
pure pure
@@ -605,8 +685,50 @@ contract LibAssetData {
decodeMultiAssetData(assetData); decodeMultiAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
decodeStaticCallAssetData(assetData); decodeStaticCallAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
decodeERC20BridgeAssetData(assetData);
} else { } else {
revert("WRONG_PROXY_ID"); revert("WRONG_PROXY_ID");
} }
} }
/// @dev Queries balance of an ERC20 token. Returns 0 if call was unsuccessful.
/// @param tokenAddress Address of ERC20 token.
/// @param ownerAddress Address of owner of ERC20 token.
/// @return balance ERC20 token balance of owner.
function _erc20BalanceOf(
address tokenAddress,
address ownerAddress
)
internal
view
returns (uint256 balance)
{
// Encode data for `balanceOf(ownerAddress)`
bytes memory balanceOfData = abi.encodeWithSelector(
IERC20Token(address(0)).balanceOf.selector,
ownerAddress
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
return balance;
}
/// @dev Converts an amount of Chai into its equivalent Dai amount.
/// Also accumulates Dai from DSR if called after the last time it was collected.
/// @param chaiAmount Amount of Chai to converts.
function _convertChaiToDaiAmount(uint256 chaiAmount)
internal
returns (uint256 daiAmount)
{
PotLike pot = IChai(_getChaiAddress()).pot();
// Accumulate savings if called after last time savings were collected
uint256 chiMultiplier = (now > pot.rho())
? pot.drip()
: pot.chi();
daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
return daiAmount;
}
} }

View File

@@ -41,6 +41,10 @@ contract OrderTransferSimulationUtils is
TransfersSuccessful // All transfers in the order were successful TransfersSuccessful // All transfers in the order were successful
} }
// NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)`
// may cause later.
address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332);
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL")); // keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0; bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
@@ -82,13 +86,13 @@ contract OrderTransferSimulationUtils is
// Transfer `makerAsset` from maker to taker // Transfer `makerAsset` from maker to taker
assetData[0] = order.makerAssetData; assetData[0] = order.makerAssetData;
fromAddresses[0] = order.makerAddress; fromAddresses[0] = order.makerAddress;
toAddresses[0] = takerAddress; toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[0] = fillResults.makerAssetFilledAmount; amounts[0] = fillResults.makerAssetFilledAmount;
// Transfer `makerFeeAsset` from maker to feeRecipient // Transfer `makerFeeAsset` from maker to feeRecipient
assetData[1] = order.makerFeeAssetData; assetData[1] = order.makerFeeAssetData;
fromAddresses[1] = order.makerAddress; fromAddresses[1] = order.makerAddress;
toAddresses[1] = order.feeRecipientAddress; toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[1] = fillResults.makerFeePaid; amounts[1] = fillResults.makerFeePaid;
return _simulateTransferFromCalls( return _simulateTransferFromCalls(
@@ -134,19 +138,19 @@ contract OrderTransferSimulationUtils is
// Transfer `makerAsset` from maker to taker // Transfer `makerAsset` from maker to taker
assetData[1] = order.makerAssetData; assetData[1] = order.makerAssetData;
fromAddresses[1] = order.makerAddress; fromAddresses[1] = order.makerAddress;
toAddresses[1] = takerAddress; toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[1] = fillResults.makerAssetFilledAmount; amounts[1] = fillResults.makerAssetFilledAmount;
// Transfer `takerFeeAsset` from taker to feeRecipient // Transfer `takerFeeAsset` from taker to feeRecipient
assetData[2] = order.takerFeeAssetData; assetData[2] = order.takerFeeAssetData;
fromAddresses[2] = takerAddress; fromAddresses[2] = takerAddress;
toAddresses[2] = order.feeRecipientAddress; toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[2] = fillResults.takerFeePaid; amounts[2] = fillResults.takerFeePaid;
// Transfer `makerFeeAsset` from maker to feeRecipient // Transfer `makerFeeAsset` from maker to feeRecipient
assetData[3] = order.makerFeeAssetData; assetData[3] = order.makerFeeAssetData;
fromAddresses[3] = order.makerAddress; fromAddresses[3] = order.makerAddress;
toAddresses[3] = order.feeRecipientAddress; toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[3] = fillResults.makerFeePaid; amounts[3] = fillResults.makerFeePaid;
return _simulateTransferFromCalls( return _simulateTransferFromCalls(

View File

@@ -35,9 +35,15 @@ contract OrderValidationUtils is
using LibBytes for bytes; using LibBytes for bytes;
using LibSafeMath for uint256; using LibSafeMath for uint256;
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
LibAssetData(_exchange) LibAssetData(
_exchange,
_chaiBridge
)
{} {}
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable. /// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
@@ -127,6 +133,18 @@ contract OrderValidationUtils is
fillableTakerAssetAmount fillableTakerAssetAmount
) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0; ) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
if (!_isAssetDataValid(order.takerAssetData)) {
fillableTakerAssetAmount = 0;
}
if (order.takerFee != 0 && !_isAssetDataValid(order.takerFeeAssetData)) {
fillableTakerAssetAmount = 0;
}
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
fillableTakerAssetAmount = 0;
}
return (orderInfo, fillableTakerAssetAmount, isValidSignature); return (orderInfo, fillableTakerAssetAmount, isValidSignature);
} }
@@ -173,11 +191,69 @@ contract OrderValidationUtils is
/// the individual asset amounts located within the `assetData`. /// the individual asset amounts located within the `assetData`.
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData) function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 transferableAssetAmount) returns (uint256 transferableAssetAmount)
{ {
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData); (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
transferableAssetAmount = LibSafeMath.min256(balance, allowance); transferableAssetAmount = LibSafeMath.min256(balance, allowance);
return transferableAssetAmount; return transferableAssetAmount;
} }
/// @dev This function handles the edge cases around taker validation. This function
/// currently attempts to find duplicate ERC721 token's in the taker
/// multiAssetData.
/// @param assetData The asset data that should be validated.
/// @return Whether or not the order should be considered valid.
function _isAssetDataValid(bytes memory assetData)
internal
pure
returns (bool)
{
// Asset data must be composed of an asset proxy Id and a bytes segment with
// a length divisible by 32.
if (assetData.length % 32 != 4) {
return false;
}
// Only process the taker asset data if it is multiAssetData.
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId != IAssetData(address(0)).MultiAsset.selector) {
return true;
}
// Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// TODO(jalextowle): Implement similar validation for non-fungible ERC1155 asset data.
bytes4 nestedAssetProxyId = nestedAssetData[i].readBytes4(0);
if (nestedAssetProxyId == IAssetData(address(0)).ERC721Token.selector) {
if (_isAssetDataDuplicated(nestedAssetData, i)) {
return false;
}
}
}
return true;
}
/// Determines whether or not asset data is duplicated later in the nested asset data.
/// @param nestedAssetData The asset data to scan for duplication.
/// @param startIdx The index where the scan should begin.
/// @return A boolean reflecting whether or not the starting asset data was duplicated.
function _isAssetDataDuplicated(
bytes[] memory nestedAssetData,
uint256 startIdx
)
internal
pure
returns (bool)
{
uint256 length = nestedAssetData.length;
for (uint256 i = startIdx + 1; i < length; i++) {
if (nestedAssetData[startIdx].equals(nestedAssetData[i])) {
return true;
}
}
}
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-dev-utils", "name": "@0x/contracts-dev-utils",
"version": "1.0.3", "version": "1.0.6",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -41,10 +41,10 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/assert": "^3.0.3", "@0x/assert": "^3.0.5",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-gen": "^2.0.6",
"@0x/sol-compiler": "^4.0.3", "@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22", "@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@types/node": "*", "@types/node": "*",
@@ -59,7 +59,7 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.0.3" "@0x/base-contract": "^6.1.2"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View File

@@ -84,7 +84,7 @@ module.exports = {
solc: { solc: {
version: '0.5.9', version: '0.5.9',
settings: { settings: {
evmVersion: 'constantinople', evmVersion: 'istanbul',
optimizer: { optimizer: {
enabled: true, enabled: true,
runs: 1000000, runs: 1000000,

View File

@@ -1,4 +1,31 @@
[ [
{
"timestamp": 1580988106,
"version": "2.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "2.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "2.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1578272714, "timestamp": 1578272714,
"version": "2.0.3", "version": "2.0.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v2.0.6 - _February 6, 2020_
* Dependencies updated
## v2.0.5 - _February 4, 2020_
* Dependencies updated
## v2.0.4 - _January 22, 2020_
* Dependencies updated
## v2.0.3 - _January 6, 2020_ ## v2.0.3 - _January 6, 2020_
* Dependencies updated * Dependencies updated

View File

@@ -4,7 +4,7 @@
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@@ -17,6 +17,7 @@
*/ */
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/LibAddress.sol"; import "@0x/contracts-utils/contracts/src/LibAddress.sol";

View File

@@ -1,4 +1,23 @@
/*
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.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./ERC1155.sol"; import "./ERC1155.sol";

View File

@@ -17,6 +17,7 @@
*/ */
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
contract MixinNonFungibleToken { contract MixinNonFungibleToken {
@@ -64,7 +65,7 @@ contract MixinNonFungibleToken {
// A base type has the NF bit but does has an index. // A base type has the NF bit but does has an index.
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0); return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
} }
/// @dev returns owner of a non-fungible token /// @dev returns owner of a non-fungible token
function ownerOf(uint256 id) public view returns (address) { function ownerOf(uint256 id) public view returns (address) {
return nfOwners[id]; return nfOwners[id];

View File

@@ -17,13 +17,14 @@
*/ */
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
/// @title ERC-1155 Multi Token Standard /// @title ERC-1155 Multi Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. /// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
interface IERC1155 { interface IERC1155 {
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, /// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
/// including zero value transfers as well as minting or burning. /// including zero value transfers as well as minting or burning.
/// Operator will always be msg.sender. /// Operator will always be msg.sender.

View File

@@ -1,4 +1,23 @@
/*
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.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "./IERC1155.sol"; import "./IERC1155.sol";

View File

@@ -17,10 +17,11 @@
*/ */
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
interface IERC1155Receiver { interface IERC1155Receiver {
/// @notice Handle the receipt of a single ERC1155 token type /// @notice Handle the receipt of a single ERC1155 token type
/// @dev The smart contract calls this function on the recipient /// @dev The smart contract calls this function on the recipient
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the /// after a `safeTransferFrom`. This function MAY throw to revert and reject the

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-erc1155", "name": "@0x/contracts-erc1155",
"version": "2.0.3", "version": "2.0.6",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -52,11 +52,11 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-gen": "^2.0.6",
"@0x/contracts-utils": "^4.0.3", "@0x/contracts-utils": "^4.2.1",
"@0x/dev-utils": "^3.1.0", "@0x/dev-utils": "^3.1.3",
"@0x/sol-compiler": "^4.0.3", "@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22", "@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1", "@0x/types": "^3.1.1",
@@ -80,10 +80,10 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.0.3", "@0x/base-contract": "^6.1.2",
"@0x/contracts-test-utils": "^5.1.0", "@0x/contracts-test-utils": "^5.1.3",
"@0x/utils": "^5.1.2", "@0x/utils": "^5.3.0",
"@0x/web3-wrapper": "^7.0.3", "@0x/web3-wrapper": "^7.0.5",
"lodash": "^4.17.11" "lodash": "^4.17.11"
}, },
"publishConfig": { "publishConfig": {

View File

@@ -1,5 +1,5 @@
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import { LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from './wrappers'; import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from './wrappers';
@@ -8,7 +8,7 @@ export class Erc1155Wrapper {
private readonly _erc1155Contract: ERC1155MintableContract; private readonly _erc1155Contract: ERC1155MintableContract;
private readonly _contractOwner: string; private readonly _contractOwner: string;
constructor(contractInstance: ERC1155MintableContract, provider: Provider, contractOwner: string) { constructor(contractInstance: ERC1155MintableContract, contractOwner: string) {
this._erc1155Contract = contractInstance; this._erc1155Contract = contractInstance;
this._contractOwner = contractOwner; this._contractOwner = contractOwner;
} }

View File

@@ -5,21 +5,18 @@ export {
IERC1155ReceiverContract, IERC1155ReceiverContract,
DummyERC1155ReceiverBatchTokenReceivedEventArgs, DummyERC1155ReceiverBatchTokenReceivedEventArgs,
ERC1155TransferSingleEventArgs, ERC1155TransferSingleEventArgs,
ERC1155TransferBatchEventArgs,
ERC1155Events,
} from './wrappers'; } from './wrappers';
export { artifacts } from './artifacts'; export { artifacts } from './artifacts';
export { Erc1155Wrapper } from './erc1155_wrapper'; export { Erc1155Wrapper } from './erc1155_wrapper';
export { export {
Provider,
TransactionReceiptWithDecodedLogs, TransactionReceiptWithDecodedLogs,
JSONRPCRequestPayload,
JSONRPCResponsePayload,
JSONRPCResponseError,
JSONRPCErrorCallback,
TransactionReceiptStatus, TransactionReceiptStatus,
ContractArtifact,
ContractChains, ContractChains,
CompilerOpts, CompilerOpts,
StandardContractOutput, StandardContractOutput,
ContractArtifact,
CompilerSettings, CompilerSettings,
ContractChainData, ContractChainData,
ContractAbi, ContractAbi,

View File

@@ -67,7 +67,7 @@ describe('ERC1155Token', () => {
); );
receiver = erc1155Receiver.address; receiver = erc1155Receiver.address;
// create wrapper & mint erc1155 tokens // create wrapper & mint erc1155 tokens
erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, provider, owner); erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, owner);
fungibleToken = await erc1155Wrapper.mintFungibleTokensAsync([spender], spenderInitialFungibleBalance); fungibleToken = await erc1155Wrapper.mintFungibleTokensAsync([spender], spenderInitialFungibleBalance);
let nonFungibleTokens: BigNumber[]; let nonFungibleTokens: BigNumber[];
[, nonFungibleTokens] = await erc1155Wrapper.mintNonFungibleTokensAsync([spender]); [, nonFungibleTokens] = await erc1155Wrapper.mintNonFungibleTokensAsync([spender]);

View File

@@ -84,7 +84,7 @@ module.exports = {
solc: { solc: {
version: '0.5.9', version: '0.5.9',
settings: { settings: {
evmVersion: 'constantinople', evmVersion: 'istanbul',
optimizer: { optimizer: {
enabled: true, enabled: true,
runs: 1000000, runs: 1000000,

View File

@@ -1,4 +1,37 @@
[ [
{
"timestamp": 1580988106,
"version": "1.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.2.0",
"changes": [
{
"note": "Make source IDs static on all networks, not inherited from `DeploymentConstants`.",
"pr": 2459
}
],
"timestamp": 1580811564
},
{
"version": "1.1.0",
"changes": [
{
"note": "Add batch functions to query quotes",
"pr": 2427
},
{
"note": "Early exit if a DEX sample fails",
"pr": 2427
}
],
"timestamp": 1579682890
},
{ {
"version": "1.0.3", "version": "1.0.3",
"changes": [ "changes": [

View File

@@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v1.2.1 - _February 6, 2020_
* Dependencies updated
## v1.2.0 - _February 4, 2020_
* Make source IDs static on all networks, not inherited from `DeploymentConstants`. (#2459)
## v1.1.0 - _January 22, 2020_
* Add batch functions to query quotes (#2427)
* Early exit if a DEX sample fails (#2427)
## v1.0.3 - _January 6, 2020_ ## v1.0.3 - _January 6, 2020_
* Add gas limits to external quote calls. (#2405) * Add gas limits to external quote calls. (#2405)

View File

@@ -4,7 +4,7 @@
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@@ -37,9 +37,76 @@ contract ERC20BridgeSampler is
DeploymentConstants DeploymentConstants
{ {
bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)")); bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)"));
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 600e3; uint256 constant internal KYBER_SAMPLE_CALL_GAS = 1500e3;
uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3; uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3;
uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 250e3; uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 1000e3;
address constant private UNISWAP_SOURCE = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
address constant private ETH2DAI_SOURCE = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
address constant private KYBER_SOURCE = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
/// @param orders Batches of Native orders to query.
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
/// @return ordersAndSamples How much taker asset can be filled
/// by each order in `orders`. Maker amounts bought for each source at
/// each taker token amount. First indexed by source index, then sample
/// index.
function queryBatchOrdersAndSampleSells(
LibOrder.Order[][] memory orders,
bytes[][] memory orderSignatures,
address[] memory sources,
uint256[][] memory takerTokenAmounts
)
public
view
returns (
OrdersAndSample[] memory ordersAndSamples
)
{
ordersAndSamples = new OrdersAndSample[](orders.length);
for (uint256 i = 0; i != orders.length; i++) {
(
uint256[] memory orderFillableAssetAmounts,
uint256[][] memory tokenAmountsBySource
) = queryOrdersAndSampleSells(orders[i], orderSignatures[i], sources, takerTokenAmounts[i]);
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
}
}
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
/// @param orders Batches of Native orders to query.
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
/// @return ordersAndSamples How much taker asset can be filled
/// by each order in `orders`. Taker amounts sold for each source at
/// each maker token amount. First indexed by source index, then sample
/// index.
function queryBatchOrdersAndSampleBuys(
LibOrder.Order[][] memory orders,
bytes[][] memory orderSignatures,
address[] memory sources,
uint256[][] memory makerTokenAmounts
)
public
view
returns (
OrdersAndSample[] memory ordersAndSamples
)
{
ordersAndSamples = new OrdersAndSample[](orders.length);
for (uint256 i = 0; i != orders.length; i++) {
(
uint256[] memory orderFillableAssetAmounts,
uint256[][] memory tokenAmountsBySource
) = queryOrdersAndSampleBuys(orders[i], orderSignatures[i], sources, makerTokenAmounts[i]);
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
}
}
/// @dev Query native orders and sample sell quotes on multiple DEXes at once. /// @dev Query native orders and sample sell quotes on multiple DEXes at once.
/// @param orders Native orders to query. /// @param orders Native orders to query.
@@ -281,6 +348,8 @@ contract ERC20BridgeSampler is
uint256 rate = 0; uint256 rate = 0;
if (didSucceed) { if (didSucceed) {
rate = abi.decode(resultData, (uint256)); rate = abi.decode(resultData, (uint256));
} else {
break;
} }
makerTokenAmounts[i] = makerTokenAmounts[i] =
rate * rate *
@@ -321,6 +390,8 @@ contract ERC20BridgeSampler is
uint256 buyAmount = 0; uint256 buyAmount = 0;
if (didSucceed) { if (didSucceed) {
buyAmount = abi.decode(resultData, (uint256)); buyAmount = abi.decode(resultData, (uint256));
} else{
break;
} }
makerTokenAmounts[i] = buyAmount; makerTokenAmounts[i] = buyAmount;
} }
@@ -356,6 +427,8 @@ contract ERC20BridgeSampler is
uint256 sellAmount = 0; uint256 sellAmount = 0;
if (didSucceed) { if (didSucceed) {
sellAmount = abi.decode(resultData, (uint256)); sellAmount = abi.decode(resultData, (uint256));
} else {
break;
} }
takerTokenAmounts[i] = sellAmount; takerTokenAmounts[i] = sellAmount;
} }
@@ -384,26 +457,28 @@ contract ERC20BridgeSampler is
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ? IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken); IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
for (uint256 i = 0; i < numSamples; i++) { for (uint256 i = 0; i < numSamples; i++) {
bool didSucceed = true;
if (makerToken == _getWethAddress()) { if (makerToken == _getWethAddress()) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction( (makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange), address(takerTokenExchange),
takerTokenExchange.getTokenToEthInputPrice.selector, takerTokenExchange.getTokenToEthInputPrice.selector,
takerTokenAmounts[i] takerTokenAmounts[i]
); );
} else if (takerToken == _getWethAddress()) { } else if (takerToken == _getWethAddress()) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction( (makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange), address(makerTokenExchange),
makerTokenExchange.getEthToTokenInputPrice.selector, makerTokenExchange.getEthToTokenInputPrice.selector,
takerTokenAmounts[i] takerTokenAmounts[i]
); );
} else { } else {
uint256 ethBought = _callUniswapExchangePriceFunction( uint256 ethBought;
(ethBought, didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange), address(takerTokenExchange),
takerTokenExchange.getTokenToEthInputPrice.selector, takerTokenExchange.getTokenToEthInputPrice.selector,
takerTokenAmounts[i] takerTokenAmounts[i]
); );
if (ethBought != 0) { if (ethBought != 0) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction( (makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange), address(makerTokenExchange),
makerTokenExchange.getEthToTokenInputPrice.selector, makerTokenExchange.getEthToTokenInputPrice.selector,
ethBought ethBought
@@ -412,6 +487,9 @@ contract ERC20BridgeSampler is
makerTokenAmounts[i] = 0; makerTokenAmounts[i] = 0;
} }
} }
if (!didSucceed) {
break;
}
} }
} }
@@ -438,26 +516,28 @@ contract ERC20BridgeSampler is
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ? IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken); IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
for (uint256 i = 0; i < numSamples; i++) { for (uint256 i = 0; i < numSamples; i++) {
bool didSucceed = true;
if (makerToken == _getWethAddress()) { if (makerToken == _getWethAddress()) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction( (takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange), address(takerTokenExchange),
takerTokenExchange.getTokenToEthOutputPrice.selector, takerTokenExchange.getTokenToEthOutputPrice.selector,
makerTokenAmounts[i] makerTokenAmounts[i]
); );
} else if (takerToken == _getWethAddress()) { } else if (takerToken == _getWethAddress()) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction( (takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange), address(makerTokenExchange),
makerTokenExchange.getEthToTokenOutputPrice.selector, makerTokenExchange.getEthToTokenOutputPrice.selector,
makerTokenAmounts[i] makerTokenAmounts[i]
); );
} else { } else {
uint256 ethSold = _callUniswapExchangePriceFunction( uint256 ethSold;
(ethSold, didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange), address(makerTokenExchange),
makerTokenExchange.getEthToTokenOutputPrice.selector, makerTokenExchange.getEthToTokenOutputPrice.selector,
makerTokenAmounts[i] makerTokenAmounts[i]
); );
if (ethSold != 0) { if (ethSold != 0) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction( (takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange), address(takerTokenExchange),
takerTokenExchange.getTokenToEthOutputPrice.selector, takerTokenExchange.getTokenToEthOutputPrice.selector,
ethSold ethSold
@@ -466,6 +546,9 @@ contract ERC20BridgeSampler is
takerTokenAmounts[i] = 0; takerTokenAmounts[i] = 0;
} }
} }
if (!didSucceed) {
break;
}
} }
} }
@@ -493,12 +576,13 @@ contract ERC20BridgeSampler is
) )
private private
view view
returns (uint256 outputAmount) returns (uint256 outputAmount, bool didSucceed)
{ {
if (uniswapExchangeAddress == address(0)) { if (uniswapExchangeAddress == address(0)) {
return 0; return (outputAmount, didSucceed);
} }
(bool didSucceed, bytes memory resultData) = bytes memory resultData;
(didSucceed, resultData) =
uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)( uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)(
abi.encodeWithSelector( abi.encodeWithSelector(
functionSelector, functionSelector,
@@ -525,13 +609,13 @@ contract ERC20BridgeSampler is
view view
returns (uint256[] memory makerTokenAmounts) returns (uint256[] memory makerTokenAmounts)
{ {
if (source == _getEth2DaiAddress()) { if (source == ETH2DAI_SOURCE) {
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts); return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
} }
if (source == _getUniswapExchangeFactoryAddress()) { if (source == UNISWAP_SOURCE) {
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts); return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
} }
if (source == _getKyberNetworkProxyAddress()) { if (source == KYBER_SOURCE) {
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts); return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
} }
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE"); revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
@@ -553,10 +637,10 @@ contract ERC20BridgeSampler is
view view
returns (uint256[] memory takerTokenAmounts) returns (uint256[] memory takerTokenAmounts)
{ {
if (source == _getEth2DaiAddress()) { if (source == ETH2DAI_SOURCE) {
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts); return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
} }
if (source == _getUniswapExchangeFactoryAddress()) { if (source == UNISWAP_SOURCE) {
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts); return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
} }
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE"); revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");

View File

@@ -23,6 +23,52 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
interface IERC20BridgeSampler { interface IERC20BridgeSampler {
struct OrdersAndSample {
uint256[] orderFillableAssetAmounts;
uint256[][] tokenAmountsBySource;
}
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
/// @param orders Batches of Native orders to query.
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
/// @return ordersAndSamples How much taker asset can be filled
/// by each order in `orders`. Maker amounts bought for each source at
/// each taker token amount. First indexed by source index, then sample
/// index.
function queryBatchOrdersAndSampleSells(
LibOrder.Order[][] calldata orders,
bytes[][] calldata orderSignatures,
address[] calldata sources,
uint256[][] calldata takerTokenAmounts
)
external
view
returns (
OrdersAndSample[] memory ordersAndSamples
);
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
/// @param orders Batches of Native orders to query.
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
/// @return ordersAndSamples How much taker asset can be filled
/// by each order in `orders`. Taker amounts sold for each source at
/// each maker token amount. First indexed by source index, then sample
/// index
function queryBatchOrdersAndSampleBuys(
LibOrder.Order[][] calldata orders,
bytes[][] calldata orderSignatures,
address[] calldata sources,
uint256[][] calldata makerTokenAmounts
)
external
view
returns (
OrdersAndSample[] memory ordersAndSamples
);
/// @dev Query native orders and sample sell quotes on multiple DEXes at once. /// @dev Query native orders and sample sell quotes on multiple DEXes at once.
/// @param orders Native orders to query. /// @param orders Native orders to query.

View File

@@ -338,7 +338,11 @@ contract TestERC20BridgeSampler is
bytes32 orderHash = keccak256(abi.encode(order.salt)); bytes32 orderHash = keccak256(abi.encode(order.salt));
// Everything else is derived from the hash. // Everything else is derived from the hash.
orderInfo.orderHash = orderHash; orderInfo.orderHash = orderHash;
orderInfo.orderStatus = LibOrder.OrderStatus(uint256(orderHash) % MAX_ORDER_STATUS); if (uint256(orderHash) % 100 > 90) {
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
} else {
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
}
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount; orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
fillableTakerAssetAmount = fillableTakerAssetAmount =
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount; order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-erc20-bridge-sampler", "name": "@0x/contracts-erc20-bridge-sampler",
"version": "1.0.3", "version": "1.2.1",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -50,18 +50,18 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/contracts-asset-proxy": "^3.1.0", "@0x/contracts-asset-proxy": "^3.1.3",
"@0x/contracts-erc20": "^3.0.3", "@0x/contracts-erc20": "^3.0.6",
"@0x/contracts-exchange": "^3.0.3", "@0x/contracts-exchange": "^3.1.2",
"@0x/contracts-exchange-libs": "^4.0.3", "@0x/contracts-exchange-libs": "^4.2.0",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-gen": "^2.0.6",
"@0x/contracts-test-utils": "^5.1.0", "@0x/contracts-test-utils": "^5.1.3",
"@0x/contracts-utils": "^4.0.3", "@0x/contracts-utils": "^4.2.1",
"@0x/dev-utils": "^3.1.0", "@0x/dev-utils": "^3.1.3",
"@0x/sol-compiler": "^4.0.3", "@0x/sol-compiler": "^4.0.6",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@0x/web3-wrapper": "^7.0.3", "@0x/web3-wrapper": "^7.0.5",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
"@types/node": "*", "@types/node": "*",
@@ -79,10 +79,10 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.0.3", "@0x/base-contract": "^6.1.2",
"@0x/types": "^3.1.1", "@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1", "@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2", "@0x/utils": "^5.3.0",
"ethereum-types": "^3.0.0", "ethereum-types": "^3.0.0",
"lodash": "^4.17.11" "lodash": "^4.17.11"
}, },

View File

@@ -15,7 +15,6 @@ import { TestERC20BridgeSamplerContract } from './wrappers';
blockchainTests('erc20-bridge-sampler', env => { blockchainTests('erc20-bridge-sampler', env => {
let testContract: TestERC20BridgeSamplerContract; let testContract: TestERC20BridgeSamplerContract;
let allSources: { [name: string]: string };
const RATE_DENOMINATOR = constants.ONE_ETHER; const RATE_DENOMINATOR = constants.ONE_ETHER;
const MIN_RATE = new BigNumber('0.01'); const MIN_RATE = new BigNumber('0.01');
const MAX_RATE = new BigNumber('100'); const MAX_RATE = new BigNumber('100');
@@ -30,6 +29,11 @@ blockchainTests('erc20-bridge-sampler', env => {
const INVALID_ASSET_DATA = hexUtils.random(37); const INVALID_ASSET_DATA = hexUtils.random(37);
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap']; const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
const BUY_SOURCES = ['Eth2Dai', 'Uniswap']; const BUY_SOURCES = ['Eth2Dai', 'Uniswap'];
const SOURCE_IDS: { [source: string]: string } = {
Uniswap: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95',
Eth2Dai: '0x39755357759ce0d7f32dc8dc45414cca409ae24e',
Kyber: '0x818e6fecd516ecc3849daf6845e3ec868087b755',
};
const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS'; const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS';
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY'; const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA'; const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
@@ -45,14 +49,6 @@ blockchainTests('erc20-bridge-sampler', env => {
env.txDefaults, env.txDefaults,
{}, {},
); );
allSources = _.zipObject(
['Uniswap', 'Eth2Dai', 'Kyber'],
[
await testContract.uniswap().callAsync(),
await testContract.eth2Dai().callAsync(),
await testContract.kyber().callAsync(),
],
);
}); });
function getPackedHash(...args: string[]): string { function getPackedHash(...args: string[]): string {
@@ -195,7 +191,7 @@ blockchainTests('erc20-bridge-sampler', env => {
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber { function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
const hash = getPackedHash(hexUtils.toHex(order.salt, 32)); const hash = getPackedHash(hexUtils.toHex(order.salt, 32));
const orderStatus = new BigNumber(hash).mod(255).toNumber(); const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber(); const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
if (orderStatus !== 3 || !isValidSignature) { if (orderStatus !== 3 || !isValidSignature) {
return constants.ZERO_AMOUNT; return constants.ZERO_AMOUNT;
@@ -208,7 +204,7 @@ blockchainTests('erc20-bridge-sampler', env => {
return order.makerAssetAmount return order.makerAssetAmount
.times(takerAmount) .times(takerAmount)
.div(order.takerAssetAmount) .div(order.takerAssetAmount)
.integerValue(BigNumber.ROUND_DOWN); .integerValue(BigNumber.ROUND_UP);
} }
function getERC20AssetData(tokenAddress: string): string { function getERC20AssetData(tokenAddress: string): string {
@@ -255,7 +251,7 @@ blockchainTests('erc20-bridge-sampler', env => {
describe('getOrderFillableTakerAssetAmounts()', () => { describe('getOrderFillableTakerAssetAmounts()', () => {
it('returns the expected amount for each order', async () => { it('returns the expected amount for each order', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN); const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const signatures: string[] = _.times(orders.length, hexUtils.random); const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const expected = orders.map(getDeterministicFillableTakerAssetAmount); const expected = orders.map(getDeterministicFillableTakerAssetAmount);
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync(); const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq(expected); expect(actual).to.deep.eq(expected);
@@ -269,7 +265,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('returns zero for an order with zero maker asset amount', async () => { it('returns zero for an order with zero maker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1); const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].makerAssetAmount = constants.ZERO_AMOUNT; orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random); const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync(); const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]); expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
}); });
@@ -277,7 +273,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('returns zero for an order with zero taker asset amount', async () => { it('returns zero for an order with zero taker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1); const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].takerAssetAmount = constants.ZERO_AMOUNT; orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random); const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync(); const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]); expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
}); });
@@ -293,7 +289,7 @@ blockchainTests('erc20-bridge-sampler', env => {
describe('getOrderFillableMakerAssetAmounts()', () => { describe('getOrderFillableMakerAssetAmounts()', () => {
it('returns the expected amount for each order', async () => { it('returns the expected amount for each order', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN); const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const signatures: string[] = _.times(orders.length, hexUtils.random); const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const expected = orders.map(getDeterministicFillableMakerAssetAmount); const expected = orders.map(getDeterministicFillableMakerAssetAmount);
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync(); const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq(expected); expect(actual).to.deep.eq(expected);
@@ -307,7 +303,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('returns zero for an order with zero maker asset amount', async () => { it('returns zero for an order with zero maker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1); const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].makerAssetAmount = constants.ZERO_AMOUNT; orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random); const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync(); const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]); expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
}); });
@@ -315,7 +311,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('returns zero for an order with zero taker asset amount', async () => { it('returns zero for an order with zero taker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1); const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].takerAssetAmount = constants.ZERO_AMOUNT; orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random); const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync(); const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]); expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
}); });
@@ -330,7 +326,7 @@ blockchainTests('erc20-bridge-sampler', env => {
describe('queryOrdersAndSampleSells()', () => { describe('queryOrdersAndSampleSells()', () => {
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN); const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random); const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
before(async () => { before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync(); await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
@@ -340,7 +336,7 @@ blockchainTests('erc20-bridge-sampler', env => {
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN); const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount); const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
const [orderInfos] = await testContract const [orderInfos] = await testContract
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), takerTokenAmounts) .queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
.callAsync(); .callAsync();
expect(orderInfos).to.deep.eq(expectedFillableAmounts); expect(orderInfos).to.deep.eq(expectedFillableAmounts);
}); });
@@ -349,14 +345,14 @@ blockchainTests('erc20-bridge-sampler', env => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN); const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts); const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
const [, quotes] = await testContract const [, quotes] = await testContract
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), sampleAmounts) .queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(expectedQuotes); expect(quotes).to.deep.eq(expectedQuotes);
}); });
it('throws if no orders are passed in', async () => { it('throws if no orders are passed in', async () => {
const tx = testContract const tx = testContract
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => allSources[n]), getSampleAmounts(TAKER_TOKEN)) .queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(TAKER_TOKEN))
.callAsync(); .callAsync();
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR); return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
}); });
@@ -366,7 +362,7 @@ blockchainTests('erc20-bridge-sampler', env => {
.queryOrdersAndSampleSells( .queryOrdersAndSampleSells(
ORDERS, ORDERS,
SIGNATURES, SIGNATURES,
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()], [...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
getSampleAmounts(TAKER_TOKEN), getSampleAmounts(TAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -381,7 +377,7 @@ blockchainTests('erc20-bridge-sampler', env => {
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
SELL_SOURCES.map(n => allSources[n]), SELL_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(TAKER_TOKEN), getSampleAmounts(TAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -396,7 +392,7 @@ blockchainTests('erc20-bridge-sampler', env => {
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
SELL_SOURCES.map(n => allSources[n]), SELL_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(TAKER_TOKEN), getSampleAmounts(TAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -411,7 +407,7 @@ blockchainTests('erc20-bridge-sampler', env => {
makerAssetData: INVALID_ASSET_DATA, makerAssetData: INVALID_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
SELL_SOURCES.map(n => allSources[n]), SELL_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(TAKER_TOKEN), getSampleAmounts(TAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -426,7 +422,7 @@ blockchainTests('erc20-bridge-sampler', env => {
takerAssetData: INVALID_ASSET_DATA, takerAssetData: INVALID_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
SELL_SOURCES.map(n => allSources[n]), SELL_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(TAKER_TOKEN), getSampleAmounts(TAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -436,7 +432,7 @@ blockchainTests('erc20-bridge-sampler', env => {
describe('queryOrdersAndSampleBuys()', () => { describe('queryOrdersAndSampleBuys()', () => {
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN); const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random); const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
before(async () => { before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync(); await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
@@ -446,7 +442,7 @@ blockchainTests('erc20-bridge-sampler', env => {
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN); const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount); const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
const [orderInfos] = await testContract const [orderInfos] = await testContract
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), takerTokenAmounts) .queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
.callAsync(); .callAsync();
expect(orderInfos).to.deep.eq(expectedFillableAmounts); expect(orderInfos).to.deep.eq(expectedFillableAmounts);
}); });
@@ -455,14 +451,14 @@ blockchainTests('erc20-bridge-sampler', env => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN); const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts); const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
const [, quotes] = await testContract const [, quotes] = await testContract
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), sampleAmounts) .queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(expectedQuotes); expect(quotes).to.deep.eq(expectedQuotes);
}); });
it('throws if no orders are passed in', async () => { it('throws if no orders are passed in', async () => {
const tx = testContract const tx = testContract
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => allSources[n]), getSampleAmounts(MAKER_TOKEN)) .queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(MAKER_TOKEN))
.callAsync(); .callAsync();
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR); return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
}); });
@@ -472,7 +468,7 @@ blockchainTests('erc20-bridge-sampler', env => {
.queryOrdersAndSampleBuys( .queryOrdersAndSampleBuys(
ORDERS, ORDERS,
SIGNATURES, SIGNATURES,
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()], [...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
getSampleAmounts(MAKER_TOKEN), getSampleAmounts(MAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -485,7 +481,7 @@ blockchainTests('erc20-bridge-sampler', env => {
.queryOrdersAndSampleBuys( .queryOrdersAndSampleBuys(
ORDERS, ORDERS,
SIGNATURES, SIGNATURES,
sources.map(n => allSources[n]), sources.map(n => SOURCE_IDS[n]),
getSampleAmounts(MAKER_TOKEN), getSampleAmounts(MAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -500,7 +496,7 @@ blockchainTests('erc20-bridge-sampler', env => {
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
BUY_SOURCES.map(n => allSources[n]), BUY_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(MAKER_TOKEN), getSampleAmounts(MAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -515,7 +511,7 @@ blockchainTests('erc20-bridge-sampler', env => {
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
BUY_SOURCES.map(n => allSources[n]), BUY_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(MAKER_TOKEN), getSampleAmounts(MAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -530,7 +526,7 @@ blockchainTests('erc20-bridge-sampler', env => {
makerAssetData: INVALID_ASSET_DATA, makerAssetData: INVALID_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
BUY_SOURCES.map(n => allSources[n]), BUY_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(MAKER_TOKEN), getSampleAmounts(MAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -545,7 +541,7 @@ blockchainTests('erc20-bridge-sampler', env => {
takerAssetData: INVALID_ASSET_DATA, takerAssetData: INVALID_ASSET_DATA,
})), })),
SIGNATURES, SIGNATURES,
BUY_SOURCES.map(n => allSources[n]), BUY_SOURCES.map(n => SOURCE_IDS[n]),
getSampleAmounts(MAKER_TOKEN), getSampleAmounts(MAKER_TOKEN),
) )
.callAsync(); .callAsync();
@@ -561,7 +557,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('returns empty quotes with no sample amounts', async () => { it('returns empty quotes with no sample amounts', async () => {
const emptyQuotes = _.times(SELL_SOURCES.length, () => []); const emptyQuotes = _.times(SELL_SOURCES.length, () => []);
const quotes = await testContract const quotes = await testContract
.sampleSells(SELL_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, []) .sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(emptyQuotes); expect(quotes).to.deep.eq(emptyQuotes);
}); });
@@ -570,7 +566,7 @@ blockchainTests('erc20-bridge-sampler', env => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN); const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts); const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
const quotes = await testContract const quotes = await testContract
.sampleSells(SELL_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) .sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(expectedQuotes); expect(quotes).to.deep.eq(expectedQuotes);
}); });
@@ -580,7 +576,7 @@ blockchainTests('erc20-bridge-sampler', env => {
const sources = _.sampleSize(SELL_SOURCES, 1); const sources = _.sampleSize(SELL_SOURCES, 1);
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts); const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
const quotes = await testContract const quotes = await testContract
.sampleSells(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) .sampleSells(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(expectedQuotes); expect(quotes).to.deep.eq(expectedQuotes);
}); });
@@ -588,7 +584,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with an unsupported source', async () => { it('throws with an unsupported source', async () => {
const tx = testContract const tx = testContract
.sampleSells( .sampleSells(
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()], [...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
TAKER_TOKEN, TAKER_TOKEN,
MAKER_TOKEN, MAKER_TOKEN,
getSampleAmounts(TAKER_TOKEN), getSampleAmounts(TAKER_TOKEN),
@@ -606,7 +602,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('returns empty quotes with no sample amounts', async () => { it('returns empty quotes with no sample amounts', async () => {
const emptyQuotes = _.times(BUY_SOURCES.length, () => []); const emptyQuotes = _.times(BUY_SOURCES.length, () => []);
const quotes = await testContract const quotes = await testContract
.sampleBuys(BUY_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, []) .sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(emptyQuotes); expect(quotes).to.deep.eq(emptyQuotes);
}); });
@@ -615,7 +611,7 @@ blockchainTests('erc20-bridge-sampler', env => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN); const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts); const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
const quotes = await testContract const quotes = await testContract
.sampleBuys(BUY_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) .sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(expectedQuotes); expect(quotes).to.deep.eq(expectedQuotes);
}); });
@@ -625,7 +621,7 @@ blockchainTests('erc20-bridge-sampler', env => {
const sources = _.sampleSize(BUY_SOURCES, 1); const sources = _.sampleSize(BUY_SOURCES, 1);
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts); const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
const quotes = await testContract const quotes = await testContract
.sampleBuys(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) .sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync(); .callAsync();
expect(quotes).to.deep.eq(expectedQuotes); expect(quotes).to.deep.eq(expectedQuotes);
}); });
@@ -633,7 +629,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with an unsupported source', async () => { it('throws with an unsupported source', async () => {
const tx = testContract const tx = testContract
.sampleBuys( .sampleBuys(
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()], [...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
TAKER_TOKEN, TAKER_TOKEN,
MAKER_TOKEN, MAKER_TOKEN,
getSampleAmounts(MAKER_TOKEN), getSampleAmounts(MAKER_TOKEN),
@@ -645,7 +641,7 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws if kyber is passed in as a source', async () => { it('throws if kyber is passed in as a source', async () => {
const sources = [...BUY_SOURCES, 'Kyber']; const sources = [...BUY_SOURCES, 'Kyber'];
const tx = testContract const tx = testContract
.sampleBuys(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN)) .sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN))
.callAsync(); .callAsync();
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR); return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
}); });

View File

@@ -84,7 +84,7 @@ module.exports = {
solc: { solc: {
version: '0.5.9', version: '0.5.9',
settings: { settings: {
evmVersion: 'constantinople', evmVersion: 'istanbul',
optimizer: { optimizer: {
enabled: true, enabled: true,
runs: 1000000, runs: 1000000,

View File

@@ -1,4 +1,31 @@
[ [
{
"timestamp": 1580988106,
"version": "3.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1578272714, "timestamp": 1578272714,
"version": "3.0.3", "version": "3.0.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v3.0.6 - _February 6, 2020_
* Dependencies updated
## v3.0.5 - _February 4, 2020_
* Dependencies updated
## v3.0.4 - _January 22, 2020_
* Dependencies updated
## v3.0.3 - _January 6, 2020_ ## v3.0.3 - _January 6, 2020_
* Dependencies updated * Dependencies updated

View File

@@ -4,7 +4,7 @@
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@@ -14,7 +14,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// solhint-disable // solhint-disable
pragma solidity ^0.4.18; pragma solidity ^0.5.9;
contract WETH9 { contract WETH9 {
@@ -30,27 +30,27 @@ contract WETH9 {
mapping (address => uint) public balanceOf; mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance; mapping (address => mapping (address => uint)) public allowance;
function() public payable { function() external payable {
deposit(); deposit();
} }
function deposit() public payable { function deposit() public payable {
balanceOf[msg.sender] += msg.value; balanceOf[msg.sender] += msg.value;
Deposit(msg.sender, msg.value); emit Deposit(msg.sender, msg.value);
} }
function withdraw(uint wad) public { function withdraw(uint wad) public {
require(balanceOf[msg.sender] >= wad); require(balanceOf[msg.sender] >= wad);
balanceOf[msg.sender] -= wad; balanceOf[msg.sender] -= wad;
msg.sender.transfer(wad); msg.sender.transfer(wad);
Withdrawal(msg.sender, wad); emit Withdrawal(msg.sender, wad);
} }
function totalSupply() public view returns (uint) { function totalSupply() public view returns (uint) {
return this.balance; return address(this).balance;
} }
function approve(address guy, uint wad) public returns (bool) { function approve(address guy, uint wad) public returns (bool) {
allowance[msg.sender][guy] = wad; allowance[msg.sender][guy] = wad;
Approval(msg.sender, guy, wad); emit Approval(msg.sender, guy, wad);
return true; return true;
} }
@@ -72,7 +72,7 @@ contract WETH9 {
balanceOf[src] -= wad; balanceOf[src] -= wad;
balanceOf[dst] += wad; balanceOf[dst] += wad;
Transfer(src, dst, wad); emit Transfer(src, dst, wad);
return true; return true;
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-erc20", "name": "@0x/contracts-erc20",
"version": "3.0.3", "version": "3.0.6",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -51,18 +51,18 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-gen": "^2.0.6",
"@0x/contracts-test-utils": "^5.1.0", "@0x/contracts-test-utils": "^5.1.3",
"@0x/contracts-utils": "^4.0.3", "@0x/contracts-utils": "^4.2.1",
"@0x/dev-utils": "^3.1.0", "@0x/dev-utils": "^3.1.3",
"@0x/sol-compiler": "^4.0.3", "@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22", "@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1", "@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1", "@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2", "@0x/utils": "^5.3.0",
"@0x/web3-wrapper": "^7.0.3", "@0x/web3-wrapper": "^7.0.5",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
"@types/node": "*", "@types/node": "*",
@@ -82,7 +82,7 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.0.3" "@0x/base-contract": "^6.1.2"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View File

@@ -1,4 +1,31 @@
[ [
{
"timestamp": 1580988106,
"version": "3.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1578272714, "timestamp": 1578272714,
"version": "3.0.3", "version": "3.0.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v3.0.6 - _February 6, 2020_
* Dependencies updated
## v3.0.5 - _February 4, 2020_
* Dependencies updated
## v3.0.4 - _January 22, 2020_
* Dependencies updated
## v3.0.3 - _January 6, 2020_ ## v3.0.3 - _January 6, 2020_
* Dependencies updated * Dependencies updated

View File

@@ -4,7 +4,7 @@
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-erc721", "name": "@0x/contracts-erc721",
"version": "3.0.3", "version": "3.0.6",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -52,18 +52,18 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-gen": "^2.0.6",
"@0x/contracts-test-utils": "^5.1.0", "@0x/contracts-test-utils": "^5.1.3",
"@0x/contracts-utils": "^4.0.3", "@0x/contracts-utils": "^4.2.1",
"@0x/dev-utils": "^3.1.0", "@0x/dev-utils": "^3.1.3",
"@0x/sol-compiler": "^4.0.3", "@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22", "@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1", "@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1", "@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2", "@0x/utils": "^5.3.0",
"@0x/web3-wrapper": "^7.0.3", "@0x/web3-wrapper": "^7.0.5",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
"@types/node": "*", "@types/node": "*",
@@ -84,7 +84,7 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.0.3" "@0x/base-contract": "^6.1.2"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View File

@@ -84,7 +84,7 @@ module.exports = {
solc: { solc: {
version: '0.5.9', version: '0.5.9',
settings: { settings: {
evmVersion: 'constantinople', evmVersion: 'istanbul',
optimizer: { optimizer: {
enabled: true, enabled: true,
runs: 1000000, runs: 1000000,

View File

@@ -1,4 +1,32 @@
[ [
{
"version": "4.1.0",
"changes": [
{
"note": "Refactor, moved LibAssetDataTransfer and MixinWeth(Utils) to extensions",
"pr": 2455
}
],
"timestamp": 1580988106
},
{
"timestamp": 1580811564,
"version": "4.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "4.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1578272714, "timestamp": 1578272714,
"version": "4.0.3", "version": "4.0.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v4.1.0 - _February 6, 2020_
* Refactor, moved LibAssetDataTransfer and MixinWeth(Utils) to extensions (#2455)
## v4.0.5 - _February 4, 2020_
* Dependencies updated
## v4.0.4 - _January 22, 2020_
* Dependencies updated
## v4.0.3 - _January 6, 2020_ ## v4.0.3 - _January 6, 2020_
* Dependencies updated * Dependencies updated

View File

@@ -4,7 +4,7 @@
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "constantinople", "evmVersion": "istanbul",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@@ -19,27 +19,191 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "./MixinForwarderCore.sol"; import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "./libs/LibConstants.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./libs/LibForwarderRichErrors.sol";
import "./MixinExchangeWrapper.sol";
import "./MixinReceiver.sol";
import "./interfaces/IForwarder.sol";
// solhint-disable no-empty-blocks
// MixinAssets, MixinExchangeWrapper, and MixinWeth are all inherited via
// MixinForwarderCore.
contract Forwarder is contract Forwarder is
LibConstants, IForwarder,
MixinForwarderCore Ownable,
MixinWethUtils,
MixinExchangeWrapper,
MixinReceiver
{ {
using LibBytes for bytes;
using LibAssetDataTransfer for bytes;
using LibSafeMath for uint256;
constructor ( constructor (
address _exchange, address _exchange,
address _exchangeV2,
address _weth address _weth
) )
public public
Ownable() Ownable()
LibConstants( MixinWethUtils(
_exchange, _exchange,
_weth _weth
) )
MixinForwarderCore() MixinExchangeWrapper(
{} _exchange,
_exchangeV2
)
{} // solhint-disable-line no-empty-blocks
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
/// that were accidentally sent to this contract.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of the asset to withdraw.
function withdrawAsset(
bytes calldata assetData,
uint256 amount
)
external
onlyOwner
{
assetData.transferOut(amount);
}
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
/// Forwarder contract to the fee recipient.
/// This method needs to be called before forwarding orders of a maker asset that hasn't
/// previously been approved.
/// @param assetData Byte array encoded for the respective asset proxy.
function approveMakerAssetProxy(bytes calldata assetData)
external
{
bytes4 proxyId = assetData.readBytes4(0);
bytes4 erc20ProxyId = IAssetData(address(0)).ERC20Token.selector;
// For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid.
if (proxyId == erc20ProxyId) {
address proxyAddress = EXCHANGE.getAssetProxy(erc20ProxyId);
if (proxyAddress == address(0)) {
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
}
address token = assetData.readAddress(16);
LibERC20Token.approve(token, proxyAddress, MAX_UINT256);
}
}
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
/// as possible, accounting for order and forwarder fees.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketSellOrdersWithEth(
LibOrder.Order[] memory orders,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{
// Pay ETH affiliate fees to all feeRecipient addresses
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
ethFeeAmounts,
feeRecipients
);
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
// and pays WETH order fees.
(
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketSellNoThrow(
orders,
wethRemaining,
signatures
);
// Ensure that no extra WETH owned by this contract has been spent.
if (wethSpentAmount > wethRemaining) {
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
wethSpentAmount,
msg.value
));
}
// Calculate amount of WETH that hasn't been spent.
wethRemaining = wethRemaining.safeSub(wethSpentAmount);
// Refund remaining ETH to msg.sender.
_unwrapAndTransferEth(wethRemaining);
}
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
/// Any ETH not spent will be refunded to sender.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketBuyOrdersWithEth(
LibOrder.Order[] memory orders,
uint256 makerAssetBuyAmount,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{
// Pay ETH affiliate fees to all feeRecipient addresses
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
ethFeeAmounts,
feeRecipients
);
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
(
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketBuyFillOrKill(
orders,
makerAssetBuyAmount,
signatures
);
// Ensure that no extra WETH owned by this contract has been spent.
if (wethSpentAmount > wethRemaining) {
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
wethSpentAmount,
msg.value
));
}
// Calculate amount of WETH that hasn't been spent.
wethRemaining = wethRemaining.safeSub(wethSpentAmount);
// Refund remaining ETH to msg.sender.
_unwrapAndTransferEth(wethRemaining);
}
} }

View File

@@ -1,140 +0,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.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol";
import "./interfaces/IAssets.sol";
contract MixinAssets is
Ownable,
LibConstants,
IAssets
{
using LibBytes for bytes;
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
/// that were accidentally sent to this contract.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of the asset to withdraw.
function withdrawAsset(
bytes calldata assetData,
uint256 amount
)
external
onlyOwner
{
_transferAssetToSender(assetData, amount);
}
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
/// Forwarder contract to the fee recipient.
/// This method needs to be called before forwarding orders of a maker asset that hasn't
/// previously been approved.
/// @param assetData Byte array encoded for the respective asset proxy.
function approveMakerAssetProxy(bytes calldata assetData)
external
{
bytes4 proxyId = assetData.readBytes4(0);
bytes4 erc20ProxyId = IAssetData(address(0)).ERC20Token.selector;
// For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid.
if (proxyId == erc20ProxyId) {
address proxyAddress = EXCHANGE.getAssetProxy(erc20ProxyId);
if (proxyAddress == address(0)) {
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
}
address token = assetData.readAddress(16);
LibERC20Token.approve(token, proxyAddress, MAX_UINT);
}
}
/// @dev Transfers given amount of asset to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function _transferAssetToSender(
bytes memory assetData,
uint256 amount
)
internal
{
bytes4 proxyId = assetData.readBytes4(0);
if (
proxyId == IAssetData(address(0)).ERC20Token.selector ||
proxyId == IAssetData(address(0)).ERC20Bridge.selector
) {
_transferERC20Token(assetData, amount);
} else if (proxyId == IAssetData(address(0)).ERC721Token.selector) {
_transferERC721Token(assetData, amount);
} else {
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
proxyId
));
}
}
/// @dev Decodes ERC20 or ERC20Bridge assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function _transferERC20Token(
bytes memory assetData,
uint256 amount
)
internal
{
address token = assetData.readAddress(16);
// Transfer tokens.
LibERC20Token.transfer(token, msg.sender, amount);
}
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function _transferERC721Token(
bytes memory assetData,
uint256 amount
)
internal
{
if (amount != 1) {
LibRichErrors.rrevert(LibForwarderRichErrors.Erc721AmountMustEqualOneError(
amount
));
}
// Decode asset data.
address token = assetData.readAddress(16);
uint256 tokenId = assetData.readUint256(36);
// Perform transfer.
IERC721Token(token).transferFrom(
address(this),
msg.sender,
tokenId
);
}
}

View File

@@ -19,27 +19,60 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "./libs/LibConstants.sol"; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./libs/LibForwarderRichErrors.sol"; import "./libs/LibForwarderRichErrors.sol";
import "./MixinAssets.sol"; import "./interfaces/IExchangeV2.sol";
contract MixinExchangeWrapper is contract MixinExchangeWrapper {
LibConstants,
MixinAssets // The v2 order id is the first 4 bytes of the ExchangeV2 order schema hash.
{ // bytes4(keccak256(abi.encodePacked(
// "Order(",
// "address makerAddress,",
// "address takerAddress,",
// "address feeRecipientAddress,",
// "address senderAddress,",
// "uint256 makerAssetAmount,",
// "uint256 takerAssetAmount,",
// "uint256 makerFee,",
// "uint256 takerFee,",
// "uint256 expirationTimeSeconds,",
// "uint256 salt,",
// "bytes makerAssetData,",
// "bytes takerAssetData",
// ")"
// )));
bytes4 constant public EXCHANGE_V2_ORDER_ID = 0x770501f8;
// solhint-disable var-name-mixedcase
IExchange internal EXCHANGE;
IExchangeV2 internal EXCHANGE_V2;
// solhint-enable var-name-mixedcase
using LibBytes for bytes; using LibBytes for bytes;
using LibAssetDataTransfer for bytes;
using LibSafeMath for uint256; using LibSafeMath for uint256;
constructor (
address _exchange,
address _exchangeV2
)
public
{
EXCHANGE = IExchange(_exchange);
EXCHANGE_V2 = IExchangeV2(_exchangeV2);
}
/// @dev Fills the input order. /// @dev Fills the input order.
/// Returns false if the transaction would otherwise revert. /// Returns false if the transaction would otherwise revert.
/// @param order Order struct containing order specifications. /// @param order Order struct containing order specifications.
@@ -54,23 +87,19 @@ contract MixinExchangeWrapper is
internal internal
returns (LibFillResults.FillResults memory fillResults) returns (LibFillResults.FillResults memory fillResults)
{ {
// ABI encode calldata for `fillOrder` if (_isV2Order(order)) {
bytes memory fillOrderCalldata = abi.encodeWithSelector( return _fillV2OrderNoThrow(
IExchange(address(0)).fillOrder.selector, order,
takerAssetFillAmount,
signature
);
}
return _fillV3OrderNoThrow(
order, order,
takerAssetFillAmount, takerAssetFillAmount,
signature signature
); );
address exchange = address(EXCHANGE);
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
if (didSucceed) {
assert(returnData.length == 160);
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
}
// fillResults values will be 0 by default if call was unsuccessful
return fillResults;
} }
/// @dev Executes a single call of fillOrder according to the wethSellAmount and /// @dev Executes a single call of fillOrder according to the wethSellAmount and
@@ -162,8 +191,7 @@ contract MixinExchangeWrapper is
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier()); uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector; bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector;
uint256 ordersLength = orders.length; for (uint256 i = 0; i != orders.length; i++) {
for (uint256 i = 0; i != ordersLength; i++) {
// Preemptively skip to avoid division by zero in _marketSellSingleOrder // Preemptively skip to avoid division by zero in _marketSellSingleOrder
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) { if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
continue; continue;
@@ -172,7 +200,7 @@ contract MixinExchangeWrapper is
// The remaining amount of WETH to sell // The remaining amount of WETH to sell
uint256 remainingTakerAssetFillAmount = wethSellAmount uint256 remainingTakerAssetFillAmount = wethSellAmount
.safeSub(totalWethSpentAmount) .safeSub(totalWethSpentAmount)
.safeSub(protocolFee); .safeSub(_isV2Order(orders[i]) ? 0 : protocolFee);
// If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance. // If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance.
bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0); bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0);
@@ -201,7 +229,7 @@ contract MixinExchangeWrapper is
); );
} }
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount); orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
totalWethSpentAmount = totalWethSpentAmount totalWethSpentAmount = totalWethSpentAmount
.safeAdd(wethSpentAmount); .safeAdd(wethSpentAmount);
@@ -349,7 +377,7 @@ contract MixinExchangeWrapper is
); );
} }
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount); orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
totalWethSpentAmount = totalWethSpentAmount totalWethSpentAmount = totalWethSpentAmount
.safeAdd(wethSpentAmount); .safeAdd(wethSpentAmount);
@@ -370,6 +398,91 @@ contract MixinExchangeWrapper is
} }
} }
/// @dev Fills the input ExchangeV2 order. The `makerFeeAssetData` must be
// equal to EXCHANGE_V2_ORDER_ID (0x770501f8).
/// Returns false if the transaction would otherwise revert.
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return Amounts filled and fees paid by maker and taker.
function _fillV2OrderNoThrow(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
internal
returns (LibFillResults.FillResults memory fillResults)
{
// Strip v3 specific fields from order
IExchangeV2.Order memory v2Order = IExchangeV2.Order({
makerAddress: order.makerAddress,
takerAddress: order.takerAddress,
feeRecipientAddress: order.feeRecipientAddress,
senderAddress: order.senderAddress,
makerAssetAmount: order.makerAssetAmount,
takerAssetAmount: order.takerAssetAmount,
// NOTE: We assume fees are 0 for all v2 orders. Orders with non-zero fees will fail to be filled.
makerFee: 0,
takerFee: 0,
expirationTimeSeconds: order.expirationTimeSeconds,
salt: order.salt,
makerAssetData: order.makerAssetData,
takerAssetData: order.takerAssetData
});
// ABI encode calldata for `fillOrder`
bytes memory fillOrderCalldata = abi.encodeWithSelector(
IExchangeV2(address(0)).fillOrder.selector,
v2Order,
takerAssetFillAmount,
signature
);
address exchange = address(EXCHANGE_V2);
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
if (didSucceed) {
assert(returnData.length == 128);
// NOTE: makerFeePaid, takerFeePaid, and protocolFeePaid will always be 0 for v2 orders
(fillResults.makerAssetFilledAmount, fillResults.takerAssetFilledAmount) = abi.decode(returnData, (uint256, uint256));
}
// fillResults values will be 0 by default if call was unsuccessful
return fillResults;
}
/// @dev Fills the input ExchangeV3 order.
/// Returns false if the transaction would otherwise revert.
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return Amounts filled and fees paid by maker and taker.
function _fillV3OrderNoThrow(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
internal
returns (LibFillResults.FillResults memory fillResults)
{
// ABI encode calldata for `fillOrder`
bytes memory fillOrderCalldata = abi.encodeWithSelector(
IExchange(address(0)).fillOrder.selector,
order,
takerAssetFillAmount,
signature
);
address exchange = address(EXCHANGE);
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
if (didSucceed) {
assert(returnData.length == 160);
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
}
// fillResults values will be 0 by default if call was unsuccessful
return fillResults;
}
/// @dev Checks whether one asset is effectively equal to another asset. /// @dev Checks whether one asset is effectively equal to another asset.
/// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if /// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if
/// one is the ERC20Bridge equivalent of the other. /// one is the ERC20Bridge equivalent of the other.
@@ -398,7 +511,18 @@ contract MixinExchangeWrapper is
address token2 = assetData2.readAddress(16); address token2 = assetData2.readAddress(16);
return (token1 == token2); return (token1 == token2);
} else { } else {
return false; return assetData1.equals(assetData2);
} }
} }
/// @dev Checks whether an order is a v2 order.
/// @param order Order struct containing order specifications.
/// @return True if the order's `makerFeeAssetData` is set to the v2 order id.
function _isV2Order(LibOrder.Order memory order)
internal
pure
returns (bool)
{
return order.makerFeeAssetData.length > 3 && order.makerFeeAssetData.readBytes4(0) == EXCHANGE_V2_ORDER_ID;
}
} }

View File

@@ -1,148 +0,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.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol";
import "./interfaces/IAssets.sol";
import "./interfaces/IForwarderCore.sol";
import "./MixinExchangeWrapper.sol";
import "./MixinWeth.sol";
contract MixinForwarderCore is
LibConstants,
IAssets,
IForwarderCore,
MixinWeth,
MixinExchangeWrapper
{
using LibBytes for bytes;
using LibSafeMath for uint256;
/// @dev Constructor approves ERC20 proxy to transfer WETH on this contract's behalf.
constructor ()
public
{
address proxyAddress = EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
if (proxyAddress == address(0)) {
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
}
ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
address protocolFeeCollector = EXCHANGE.protocolFeeCollector();
if (protocolFeeCollector != address(0)) {
ETHER_TOKEN.approve(protocolFeeCollector, MAX_UINT);
}
}
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
/// as possible, accounting for order and forwarder fees.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketSellOrdersWithEth(
LibOrder.Order[] memory orders,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{
// Pay ETH affiliate fees to all feeRecipient addresses
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
ethFeeAmounts,
feeRecipients
);
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
// and pays WETH order fees.
(
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketSellNoThrow(
orders,
wethRemaining,
signatures
);
// Refund remaining ETH to msg.sender.
_transferEthRefund(wethRemaining, wethSpentAmount);
}
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
/// Any ETH not spent will be refunded to sender.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketBuyOrdersWithEth(
LibOrder.Order[] memory orders,
uint256 makerAssetBuyAmount,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{
// Pay ETH affiliate fees to all feeRecipient addresses
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
ethFeeAmounts,
feeRecipients
);
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
(
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketBuyFillOrKill(
orders,
makerAssetBuyAmount,
signatures
);
// Refund remaining ETH to msg.sender.
_transferEthRefund(wethRemaining, wethSpentAmount);
}
}

View File

@@ -0,0 +1,76 @@
/*
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.5.9;
contract MixinReceiver {
bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61;
bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81;
/// @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 `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
)
external
returns (bytes4)
{
return ERC1155_RECEIVED;
}
/// @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 `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external
returns (bytes4)
{
return ERC1155_BATCH_RECEIVED;
}
}

View File

@@ -1,45 +0,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.5.9;
contract IAssets {
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
/// used to withdraw assets that were accidentally sent to this contract.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of ERC20 token to withdraw.
function withdrawAsset(
bytes calldata assetData,
uint256 amount
)
external;
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
/// Forwarder contract to the fee recipient.
/// This method needs to be called before forwarding orders of a maker asset that hasn't
/// previously been approved.
/// @param assetData Byte array encoded for the respective asset proxy.
function approveMakerAssetProxy(
bytes calldata assetData
)
external;
}

View File

@@ -0,0 +1,75 @@
/*
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.5.9;
pragma experimental ABIEncoderV2;
contract IExchangeV2 {
// solhint-disable max-line-length
struct Order {
address makerAddress; // Address that created the order.
address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order.
address feeRecipientAddress; // Address that will recieve fees when order is filled.
address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.
uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0.
uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0.
uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.
uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.
uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires.
uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash.
bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.
bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.
}
// solhint-enable max-line-length
struct FillResults {
uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled.
uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled.
uint256 makerFeePaid; // Total amount of ZRX paid by maker(s) to feeRecipient(s).
uint256 takerFeePaid; // Total amount of ZRX paid by taker to feeRecipients(s).
}
struct OrderInfo {
uint8 orderStatus; // Status that describes order's validity and fillability.
bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash).
uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
}
/// @dev Fills the input order.
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return Amounts filled and fees paid by maker and taker.
function fillOrder(
Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
public
returns (FillResults memory fillResults);
/// @dev Gets information about an order: status, hash, and amount filled.
/// @param order Order to gather information on.
/// @return OrderInfo Information about the order and its state.
/// See LibOrder.OrderInfo for a complete description.
function getOrderInfo(Order memory order)
public
returns (OrderInfo memory orderInfo);
}

View File

@@ -19,12 +19,77 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "./IForwarderCore.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "./IAssets.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
// solhint-disable no-empty-blocks contract IForwarder {
contract IForwarder is
IForwarderCore, /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
IAssets /// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
{} /// used to withdraw assets that were accidentally sent to this contract.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of ERC20 token to withdraw.
function withdrawAsset(
bytes calldata assetData,
uint256 amount
)
external;
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
/// Forwarder contract to the fee recipient.
/// This method needs to be called before forwarding orders of a maker asset that hasn't
/// previously been approved.
/// @param assetData Byte array encoded for the respective asset proxy.
function approveMakerAssetProxy(
bytes calldata assetData
)
external;
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
/// as possible, accounting for order and forwarder fees.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketSellOrdersWithEth(
LibOrder.Order[] memory orders,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
);
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
/// Any ETH not spent will be refunded to sender.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketBuyOrdersWithEth(
LibOrder.Order[] memory orders,
uint256 makerAssetBuyAmount,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
);
}

View File

@@ -1,73 +0,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.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
contract IForwarderCore {
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
/// as possible, accounting for order and forwarder fees.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketSellOrdersWithEth(
LibOrder.Order[] memory orders,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
);
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
/// Any ETH not spent will be refunded to sender.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
/// @param signatures Proofs that orders have been created by makers.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
function marketBuyOrdersWithEth(
LibOrder.Order[] memory orders,
uint256 makerAssetBuyAmount,
bytes[] memory signatures,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
);
}

View File

@@ -1,46 +0,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.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
contract LibConstants {
using LibBytes for bytes;
uint256 constant internal MAX_UINT = 2**256 - 1;
// solhint-disable var-name-mixedcase
IExchange internal EXCHANGE;
IEtherToken internal ETHER_TOKEN;
// solhint-enable var-name-mixedcase
constructor (
address _exchange,
address _weth
)
public
{
EXCHANGE = IExchange(_exchange);
ETHER_TOKEN = IEtherToken(_weth);
}
}

View File

@@ -25,10 +25,6 @@ library LibForwarderRichErrors {
bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR = bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR =
0xf3b96b8d; 0xf3b96b8d;
// bytes4(keccak256("UnsupportedAssetProxyError(bytes4)"))
bytes4 internal constant UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR =
0x7996a271;
// bytes4(keccak256("CompleteBuyFailedError(uint256,uint256)")) // bytes4(keccak256("CompleteBuyFailedError(uint256,uint256)"))
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR = bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
0x91353a0c; 0x91353a0c;
@@ -37,26 +33,10 @@ library LibForwarderRichErrors {
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR = bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
0x31360af1; 0x31360af1;
// bytes4(keccak256("InsufficientEthForFeeError(uint256,uint256)"))
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
0xecf40fd9;
// bytes4(keccak256("OverspentWethError(uint256,uint256)")) // bytes4(keccak256("OverspentWethError(uint256,uint256)"))
bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR = bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR =
0xcdcbed5d; 0xcdcbed5d;
// bytes4(keccak256("DefaultFunctionWethContractOnlyError(address)"))
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
0x08b18698;
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
0xbaffa474;
// bytes4(keccak256("EthFeeLengthMismatchError(uint256,uint256)"))
bytes4 internal constant ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR =
0x3ecb6ceb;
// solhint-disable func-name-mixedcase // solhint-disable func-name-mixedcase
function UnregisteredAssetProxyError() function UnregisteredAssetProxyError()
internal internal
@@ -66,19 +46,6 @@ library LibForwarderRichErrors {
return abi.encodeWithSelector(UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR); return abi.encodeWithSelector(UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR);
} }
function UnsupportedAssetProxyError(
bytes4 proxyId
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR,
proxyId
);
}
function CompleteBuyFailedError( function CompleteBuyFailedError(
uint256 expectedAssetBuyAmount, uint256 expectedAssetBuyAmount,
uint256 actualAssetBuyAmount uint256 actualAssetBuyAmount
@@ -107,21 +74,6 @@ library LibForwarderRichErrors {
); );
} }
function InsufficientEthForFeeError(
uint256 ethFeeRequired,
uint256 ethAvailable
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR,
ethFeeRequired,
ethAvailable
);
}
function OverspentWethError( function OverspentWethError(
uint256 wethSpent, uint256 wethSpent,
uint256 msgValue uint256 msgValue
@@ -136,45 +88,4 @@ library LibForwarderRichErrors {
msgValue msgValue
); );
} }
function DefaultFunctionWethContractOnlyError(
address senderAddress
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR,
senderAddress
);
}
function Erc721AmountMustEqualOneError(
uint256 amount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR,
amount
);
}
function EthFeeLengthMismatchError(
uint256 ethFeesLength,
uint256 feeRecipientsLength
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR,
ethFeesLength,
feeRecipientsLength
);
}
} }

View File

@@ -19,18 +19,21 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
import "../src/MixinExchangeWrapper.sol"; import "../src/MixinExchangeWrapper.sol";
import "../src/libs/LibConstants.sol"; import "../src/MixinReceiver.sol";
contract TestForwarder is contract TestForwarder is
LibConstants, MixinExchangeWrapper,
MixinExchangeWrapper MixinReceiver
{ {
using LibAssetDataTransfer for bytes;
// solhint-disable no-empty-blocks // solhint-disable no-empty-blocks
constructor () constructor ()
public public
LibConstants( MixinExchangeWrapper(
address(0), address(0),
address(0) address(0)
) )
@@ -49,15 +52,12 @@ contract TestForwarder is
); );
} }
function transferAssetToSender( function transferOut(
bytes memory assetData, bytes memory assetData,
uint256 amount uint256 amount
) )
public public
{ {
_transferAssetToSender( assetData.transferOut(amount);
assetData,
amount
);
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-exchange-forwarder", "name": "@0x/contracts-exchange-forwarder",
"version": "4.0.3", "version": "4.1.0",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -38,8 +38,8 @@
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
}, },
"config": { "config": {
"publicInterfaceContracts": "Forwarder", "publicInterfaceContracts": "Forwarder,IExchangeV2",
"abis": "./test/generated-artifacts/@(Forwarder|IAssets|IForwarder|IForwarderCore|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinWeth|TestForwarder).json", "abis": "./test/generated-artifacts/@(Forwarder|IExchangeV2|IForwarder|LibForwarderRichErrors|MixinExchangeWrapper|MixinReceiver|TestForwarder).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
}, },
"repository": { "repository": {
@@ -52,24 +52,25 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.0.3", "@0x/abi-gen": "^5.1.2",
"@0x/contracts-asset-proxy": "^3.1.0", "@0x/contracts-asset-proxy": "^3.1.3",
"@0x/contracts-dev-utils": "^1.0.3", "@0x/contracts-dev-utils": "^1.0.6",
"@0x/contracts-erc20": "^3.0.3", "@0x/contracts-erc1155": "^2.0.6",
"@0x/contracts-erc721": "^3.0.3", "@0x/contracts-erc20": "^3.0.6",
"@0x/contracts-exchange": "^3.0.3", "@0x/contracts-erc721": "^3.0.6",
"@0x/contracts-exchange-libs": "^4.0.3", "@0x/contracts-exchange": "^3.1.2",
"@0x/contracts-gen": "^2.0.3", "@0x/contracts-exchange-libs": "^4.2.0",
"@0x/contracts-test-utils": "^5.1.0", "@0x/contracts-gen": "^2.0.6",
"@0x/contracts-utils": "^4.0.3", "@0x/contracts-test-utils": "^5.1.3",
"@0x/dev-utils": "^3.1.0", "@0x/contracts-utils": "^4.2.1",
"@0x/order-utils": "^10.1.0", "@0x/dev-utils": "^3.1.3",
"@0x/sol-compiler": "^4.0.3", "@0x/order-utils": "^10.1.3",
"@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22", "@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1", "@0x/types": "^3.1.1",
"@0x/utils": "^5.1.2", "@0x/utils": "^5.3.0",
"@0x/web3-wrapper": "^7.0.3", "@0x/web3-wrapper": "^7.0.5",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
"@types/node": "*", "@types/node": "*",
@@ -89,7 +90,7 @@
"typescript": "3.0.1" "typescript": "3.0.1"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.0.3", "@0x/base-contract": "^6.1.2",
"@0x/typescript-typings": "^5.0.1", "@0x/typescript-typings": "^5.0.1",
"ethereum-types": "^3.0.0" "ethereum-types": "^3.0.0"
}, },

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