Compare commits

..

132 Commits

Author SHA1 Message Date
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
348 changed files with 11257 additions and 4371 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,10 +18,22 @@
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
contract IChai {
contract IChai is
IERC20Token
{
/// @dev Withdraws Dai owned by `src`
/// @param src Address that owns Dai.
/// @param wad Amount of Dai to withdraw.
@@ -30,4 +42,25 @@ contract IChai {
uint256 wad
)
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",
"version": "3.1.0",
"version": "3.1.2",
"engines": {
"node": ">=6.12"
},
@@ -51,12 +51,12 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/abi-gen": "^5.1.1",
"@0x/contracts-gen": "^2.0.5",
"@0x/contracts-test-utils": "^5.1.2",
"@0x/contracts-utils": "^4.2.0",
"@0x/dev-utils": "^3.1.2",
"@0x/sol-compiler": "^4.0.5",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1",
@@ -79,16 +79,16 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.3",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc1155": "^2.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-erc721": "^3.0.3",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/order-utils": "^10.1.0",
"@0x/base-contract": "^6.1.1",
"@0x/contracts-dev-utils": "^1.0.5",
"@0x/contracts-erc1155": "^2.0.5",
"@0x/contracts-erc20": "^3.0.5",
"@0x/contracts-erc721": "^3.0.5",
"@0x/contracts-exchange-libs": "^4.1.1",
"@0x/order-utils": "^10.1.2",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"@0x/utils": "^5.2.0",
"@0x/web3-wrapper": "^7.0.4",
"ethereum-types": "^3.0.0",
"lodash": "^4.17.11"
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,25 +26,33 @@ import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "./OrderValidationUtils.sol";
import "./OrderTransferSimulationUtils.sol";
import "./LibTransactionDecoder.sol";
import "./EthBalanceChecker.sol";
// solhint-disable no-empty-blocks
contract DevUtils is
OrderValidationUtils,
LibTransactionDecoder,
LibEIP712ExchangeDomain,
EthBalanceChecker
{
constructor (address _exchange)
constructor (
address _exchange,
address _chaiBridge
)
public
OrderValidationUtils(_exchange)
OrderValidationUtils(
_exchange,
_chaiBridge
)
OrderTransferSimulationUtils(_exchange)
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
pure
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-erc721/contracts/src/interfaces/IERC721Token.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
uint256 constant internal _MAX_UINT256 = uint256(-1);
@@ -41,9 +45,13 @@ contract LibAssetData {
address internal _ERC721_PROXY_ADDRESS;
address internal _ERC1155_PROXY_ADDRESS;
address internal _STATIC_CALL_PROXY_ADDRESS;
address internal _CHAI_BRIDGE_ADDRESS;
// solhint-enable var-name-mixedcase
constructor (address _exchange)
constructor (
address _exchange,
address _chaiBridge
)
public
{
_EXCHANGE = IExchange(_exchange);
@@ -51,6 +59,7 @@ contract LibAssetData {
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.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
@@ -62,7 +71,6 @@ contract LibAssetData {
/// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 balance)
{
// Get id of AssetProxy contract
@@ -71,16 +79,8 @@ contract LibAssetData {
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
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) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
@@ -94,12 +94,18 @@ contract LibAssetData {
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address, array of ids, and array of values
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
uint256 length = tokenIds.length;
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])
bytes memory balanceOfData = abi.encodeWithSelector(
IERC1155(address(0)).balanceOf.selector,
@@ -113,10 +119,14 @@ contract LibAssetData {
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / tokenValues[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
bytes memory transferFromData = abi.encodeWithSelector(
@@ -132,17 +142,36 @@ contract LibAssetData {
// Success means that the staticcall can be made an unlimited amount of times
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) {
// 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++) {
// Skip over the asset if the corresponding amount is 0.
if (assetAmounts[i] == 0) {
continue;
}
// Query balance of individual assetData
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / assetAmounts[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
@@ -160,7 +189,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public
view
returns (uint256[] memory balances)
{
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.
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 allowance)
{
// Get id of AssetProxy contract
@@ -193,11 +220,19 @@ contract LibAssetData {
uint256 length = nestedAssetData.length;
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
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
// Scale total allowance down by corresponding value in assetData
uint256 scaledAllowance = totalAllowance / amounts[i];
if (scaledAllowance == 0) {
return 0;
}
if (scaledAllowance < allowance || allowance == 0) {
allowance = scaledAllowance;
}
@@ -219,6 +254,7 @@ contract LibAssetData {
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
@@ -244,6 +280,7 @@ contract LibAssetData {
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
allowance = _MAX_UINT256;
}
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
@@ -258,9 +295,26 @@ contract LibAssetData {
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// The StaticCallProxy does not require any approvals
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
@@ -274,7 +328,6 @@ contract LibAssetData {
/// element corresponding to the same-indexed element in the assetData input.
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
view
returns (uint256[] memory allowances)
{
uint256 length = assetData.length;
@@ -292,7 +345,6 @@ contract LibAssetData {
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 balance, uint256 allowance)
{
balance = getBalance(ownerAddress, assetData);
@@ -308,7 +360,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
view
returns (uint256[] memory balances, uint256[] memory allowances)
{
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)
public
pure
@@ -605,8 +685,50 @@ contract LibAssetData {
decodeMultiAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
decodeStaticCallAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
decodeERC20BridgeAssetData(assetData);
} else {
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
}
// 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"));
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
@@ -82,13 +86,13 @@ contract OrderTransferSimulationUtils is
// Transfer `makerAsset` from maker to taker
assetData[0] = order.makerAssetData;
fromAddresses[0] = order.makerAddress;
toAddresses[0] = takerAddress;
toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[0] = fillResults.makerAssetFilledAmount;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[1] = order.makerFeeAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = order.feeRecipientAddress;
toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[1] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(
@@ -134,19 +138,19 @@ contract OrderTransferSimulationUtils is
// Transfer `makerAsset` from maker to taker
assetData[1] = order.makerAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = takerAddress;
toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[1] = fillResults.makerAssetFilledAmount;
// Transfer `takerFeeAsset` from taker to feeRecipient
assetData[2] = order.takerFeeAssetData;
fromAddresses[2] = takerAddress;
toAddresses[2] = order.feeRecipientAddress;
toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[2] = fillResults.takerFeePaid;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[3] = order.makerFeeAssetData;
fromAddresses[3] = order.makerAddress;
toAddresses[3] = order.feeRecipientAddress;
toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[3] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(

View File

@@ -35,9 +35,15 @@ contract OrderValidationUtils is
using LibBytes for bytes;
using LibSafeMath for uint256;
constructor (address _exchange)
constructor (
address _exchange,
address _chaiBridge
)
public
LibAssetData(_exchange)
LibAssetData(
_exchange,
_chaiBridge
)
{}
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
@@ -127,6 +133,18 @@ contract OrderValidationUtils is
fillableTakerAssetAmount
) == 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);
}
@@ -173,11 +191,69 @@ contract OrderValidationUtils is
/// the individual asset amounts located within the `assetData`.
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 transferableAssetAmount)
{
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
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",
"version": "1.0.3",
"version": "1.0.5",
"engines": {
"node": ">=6.12"
},
@@ -41,10 +41,10 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.3",
"@0x/assert": "^3.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/sol-compiler": "^4.0.3",
"@0x/abi-gen": "^5.1.1",
"@0x/assert": "^3.0.4",
"@0x/contracts-gen": "^2.0.5",
"@0x/sol-compiler": "^4.0.5",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@types/node": "*",
@@ -59,7 +59,7 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.3"
"@0x/base-contract": "^6.1.1"
},
"publishConfig": {
"access": "public"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,6 +17,7 @@
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
contract MixinNonFungibleToken {
@@ -64,7 +65,7 @@ contract MixinNonFungibleToken {
// 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);
}
/// @dev returns owner of a non-fungible token
function ownerOf(uint256 id) public view returns (address) {
return nfOwners[id];

View File

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

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 experimental ABIEncoderV2;
import "./IERC1155.sol";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,28 @@
[
{
"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",
"changes": [

View File

@@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## 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_
* Add gas limits to external quote calls. (#2405)

View File

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

View File

@@ -37,9 +37,76 @@ contract ERC20BridgeSampler is
DeploymentConstants
{
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 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.
/// @param orders Native orders to query.
@@ -281,6 +348,8 @@ contract ERC20BridgeSampler is
uint256 rate = 0;
if (didSucceed) {
rate = abi.decode(resultData, (uint256));
} else {
break;
}
makerTokenAmounts[i] =
rate *
@@ -321,6 +390,8 @@ contract ERC20BridgeSampler is
uint256 buyAmount = 0;
if (didSucceed) {
buyAmount = abi.decode(resultData, (uint256));
} else{
break;
}
makerTokenAmounts[i] = buyAmount;
}
@@ -356,6 +427,8 @@ contract ERC20BridgeSampler is
uint256 sellAmount = 0;
if (didSucceed) {
sellAmount = abi.decode(resultData, (uint256));
} else {
break;
}
takerTokenAmounts[i] = sellAmount;
}
@@ -384,26 +457,28 @@ contract ERC20BridgeSampler is
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
for (uint256 i = 0; i < numSamples; i++) {
bool didSucceed = true;
if (makerToken == _getWethAddress()) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthInputPrice.selector,
takerTokenAmounts[i]
);
} else if (takerToken == _getWethAddress()) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenInputPrice.selector,
takerTokenAmounts[i]
);
} else {
uint256 ethBought = _callUniswapExchangePriceFunction(
uint256 ethBought;
(ethBought, didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthInputPrice.selector,
takerTokenAmounts[i]
);
if (ethBought != 0) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenInputPrice.selector,
ethBought
@@ -412,6 +487,9 @@ contract ERC20BridgeSampler is
makerTokenAmounts[i] = 0;
}
}
if (!didSucceed) {
break;
}
}
}
@@ -438,26 +516,28 @@ contract ERC20BridgeSampler is
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
for (uint256 i = 0; i < numSamples; i++) {
bool didSucceed = true;
if (makerToken == _getWethAddress()) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthOutputPrice.selector,
makerTokenAmounts[i]
);
} else if (takerToken == _getWethAddress()) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenOutputPrice.selector,
makerTokenAmounts[i]
);
} else {
uint256 ethSold = _callUniswapExchangePriceFunction(
uint256 ethSold;
(ethSold, didSucceed) = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenOutputPrice.selector,
makerTokenAmounts[i]
);
if (ethSold != 0) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthOutputPrice.selector,
ethSold
@@ -466,6 +546,9 @@ contract ERC20BridgeSampler is
takerTokenAmounts[i] = 0;
}
}
if (!didSucceed) {
break;
}
}
}
@@ -493,12 +576,13 @@ contract ERC20BridgeSampler is
)
private
view
returns (uint256 outputAmount)
returns (uint256 outputAmount, bool didSucceed)
{
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)(
abi.encodeWithSelector(
functionSelector,
@@ -525,13 +609,13 @@ contract ERC20BridgeSampler is
view
returns (uint256[] memory makerTokenAmounts)
{
if (source == _getEth2DaiAddress()) {
if (source == ETH2DAI_SOURCE) {
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
}
if (source == _getUniswapExchangeFactoryAddress()) {
if (source == UNISWAP_SOURCE) {
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
}
if (source == _getKyberNetworkProxyAddress()) {
if (source == KYBER_SOURCE) {
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
}
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
@@ -553,10 +637,10 @@ contract ERC20BridgeSampler is
view
returns (uint256[] memory takerTokenAmounts)
{
if (source == _getEth2DaiAddress()) {
if (source == ETH2DAI_SOURCE) {
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
}
if (source == _getUniswapExchangeFactoryAddress()) {
if (source == UNISWAP_SOURCE) {
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
}
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");

View File

@@ -23,6 +23,52 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
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.
/// @param orders Native orders to query.

View File

@@ -338,7 +338,11 @@ contract TestERC20BridgeSampler is
bytes32 orderHash = keccak256(abi.encode(order.salt));
// Everything else is derived from the hash.
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;
fillableTakerAssetAmount =
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1580811564,
"version": "4.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "4.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1578272714,
"version": "4.0.3",

View File

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

View File

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

View File

@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
import "./MixinForwarderCore.sol";
import "./libs/LibConstants.sol";
import "./MixinReceiver.sol";
// solhint-disable no-empty-blocks
@@ -28,16 +29,19 @@ import "./libs/LibConstants.sol";
// MixinForwarderCore.
contract Forwarder is
LibConstants,
MixinForwarderCore
MixinForwarderCore,
MixinReceiver
{
constructor (
address _exchange,
address _exchangeV2,
address _weth
)
public
Ownable()
LibConstants(
_exchange,
_exchangeV2,
_weth
)
MixinForwarderCore()

View File

@@ -22,9 +22,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/LibAssetDataTransfer.sol";
import "./libs/LibForwarderRichErrors.sol";
import "./interfaces/IAssets.sol";
@@ -35,6 +35,7 @@ contract MixinAssets is
IAssets
{
using LibBytes for bytes;
using LibAssetDataTransfer 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.
@@ -47,7 +48,7 @@ contract MixinAssets is
external
onlyOwner
{
_transferAssetToSender(assetData, amount);
assetData.transferOut(amount);
}
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
@@ -72,69 +73,4 @@ contract MixinAssets is
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

@@ -30,6 +30,7 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol";
import "./interfaces/IExchangeV2.sol";
import "./MixinAssets.sol";
@@ -54,23 +55,19 @@ contract MixinExchangeWrapper is
internal
returns (LibFillResults.FillResults memory fillResults)
{
// ABI encode calldata for `fillOrder`
bytes memory fillOrderCalldata = abi.encodeWithSelector(
IExchange(address(0)).fillOrder.selector,
if (_isV2Order(order)) {
return _fillV2OrderNoThrow(
order,
takerAssetFillAmount,
signature
);
}
return _fillV3OrderNoThrow(
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 Executes a single call of fillOrder according to the wethSellAmount and
@@ -162,8 +159,7 @@ contract MixinExchangeWrapper is
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector;
uint256 ordersLength = orders.length;
for (uint256 i = 0; i != ordersLength; i++) {
for (uint256 i = 0; i != orders.length; i++) {
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
continue;
@@ -172,7 +168,7 @@ contract MixinExchangeWrapper is
// The remaining amount of WETH to sell
uint256 remainingTakerAssetFillAmount = wethSellAmount
.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.
bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0);
@@ -201,7 +197,7 @@ contract MixinExchangeWrapper is
);
}
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
totalWethSpentAmount = totalWethSpentAmount
.safeAdd(wethSpentAmount);
@@ -349,7 +345,7 @@ contract MixinExchangeWrapper is
);
}
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
totalWethSpentAmount = totalWethSpentAmount
.safeAdd(wethSpentAmount);
@@ -370,6 +366,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.
/// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if
/// one is the ERC20Bridge equivalent of the other.
@@ -398,7 +479,18 @@ contract MixinExchangeWrapper is
address token2 = assetData2.readAddress(16);
return (token1 == token2);
} 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

@@ -85,7 +85,6 @@ contract MixinForwarderCore is
ethFeeAmounts,
feeRecipients
);
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
// and pays WETH order fees.
(

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

@@ -109,7 +109,6 @@ contract MixinWeth is
if (wethRemaining > 0) {
// Convert remaining WETH to ETH
ETHER_TOKEN.withdraw(wethRemaining);
// Transfer remaining ETH to sender
msg.sender.transfer(wethRemaining);
}

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

@@ -0,0 +1,258 @@
/*
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-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "./LibForwarderRichErrors.sol";
library LibAssetDataTransfer {
using LibBytes for bytes;
using LibSafeMath for uint256;
using LibAssetDataTransfer for bytes;
/// @dev Transfers given amount of asset to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer to sender.
function transferFrom(
bytes memory assetData,
address from,
address to,
uint256 amount
)
internal
{
if (amount == 0) {
return;
}
bytes4 proxyId = assetData.readBytes4(0);
if (
proxyId == IAssetData(address(0)).ERC20Token.selector ||
proxyId == IAssetData(address(0)).ERC20Bridge.selector
) {
assetData.transferERC20Token(
from,
to,
amount
);
} else if (proxyId == IAssetData(address(0)).ERC721Token.selector) {
assetData.transferERC721Token(
from,
to,
amount
);
} else if (proxyId == IAssetData(address(0)).ERC1155Assets.selector) {
assetData.transferERC1155Assets(
from,
to,
amount
);
} else if (proxyId == IAssetData(address(0)).MultiAsset.selector) {
assetData.transferMultiAsset(
from,
to,
amount
);
} else if (proxyId != IAssetData(address(0)).StaticCall.selector) {
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
proxyId
));
}
}
///@dev Transfer asset from sender to this contract.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferIn(
bytes memory assetData,
uint256 amount
)
internal
{
assetData.transferFrom(
msg.sender,
address(this),
amount
);
}
///@dev Transfer asset from this contract to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferOut(
bytes memory assetData,
uint256 amount
)
internal
{
assetData.transferFrom(
address(this),
msg.sender,
amount
);
}
/// @dev Decodes ERC20 or ERC20Bridge assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer to sender.
function transferERC20Token(
bytes memory assetData,
address from,
address to,
uint256 amount
)
internal
{
address token = assetData.readAddress(16);
// Transfer tokens.
if (from == address(this)) {
LibERC20Token.transfer(
token,
to,
amount
);
} else {
LibERC20Token.transferFrom(
token,
from,
to,
amount
);
}
}
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer to sender.
function transferERC721Token(
bytes memory assetData,
address from,
address to,
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(
from,
to,
tokenId
);
}
/// @dev Decodes ERC1155 assetData and transfers given amounts to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer to sender.
function transferERC1155Assets(
bytes memory assetData,
address from,
address to,
uint256 amount
)
internal
{
// Decode assetData
// solhint-disable
(
address token,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) = abi.decode(
assetData.slice(4, assetData.length),
(address, uint256[], uint256[], bytes)
);
// solhint-enable
// Scale up values by `amount`
uint256 length = values.length;
uint256[] memory scaledValues = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
scaledValues[i] = values[i].safeMul(amount);
}
// Execute `safeBatchTransferFrom` call
// Either succeeds or throws
IERC1155(token).safeBatchTransferFrom(
from,
to,
ids,
scaledValues,
data
);
}
/// @dev Decodes MultiAsset assetData and recursively transfers assets to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer to sender.
function transferMultiAsset(
bytes memory assetData,
address from,
address to,
uint256 amount
)
internal
{
// solhint-disable indent
(uint256[] memory nestedAmounts, bytes[] memory nestedAssetData) = abi.decode(
assetData.slice(4, assetData.length),
(uint256[], bytes[])
);
// solhint-enable indent
uint256 numNestedAssets = nestedAssetData.length;
for (uint256 i = 0; i != numNestedAssets; i++) {
transferFrom(
nestedAssetData[i],
from,
to,
amount.safeMul(nestedAmounts[i])
);
}
}
}

View File

@@ -18,29 +18,49 @@
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";
import "../interfaces/IExchangeV2.sol";
contract LibConstants {
using LibBytes for bytes;
uint256 constant internal MAX_UINT = uint256(-1);
uint256 constant internal MAX_UINT = 2**256 - 1;
// 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;
IEtherToken internal ETHER_TOKEN;
// solhint-enable var-name-mixedcase
constructor (
address _exchange,
address _exchangeV2,
address _weth
)
public
{
EXCHANGE = IExchange(_exchange);
EXCHANGE_V2 = IExchangeV2(_exchangeV2);
ETHER_TOKEN = IEtherToken(_weth);
}
}

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-forwarder",
"version": "4.0.3",
"version": "4.0.5",
"engines": {
"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"
},
"config": {
"publicInterfaceContracts": "Forwarder",
"abis": "./test/generated-artifacts/@(Forwarder|IAssets|IForwarder|IForwarderCore|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinWeth|TestForwarder).json",
"publicInterfaceContracts": "Forwarder,IExchangeV2",
"abis": "./test/generated-artifacts/@(Forwarder|IAssets|IExchangeV2|IForwarder|IForwarderCore|LibAssetDataTransfer|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinReceiver|MixinWeth|TestForwarder).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
@@ -52,24 +52,25 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-asset-proxy": "^3.1.0",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-erc721": "^3.0.3",
"@0x/contracts-exchange": "^3.0.3",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/order-utils": "^10.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/abi-gen": "^5.1.1",
"@0x/contracts-asset-proxy": "^3.1.2",
"@0x/contracts-dev-utils": "^1.0.5",
"@0x/contracts-erc1155": "^2.0.5",
"@0x/contracts-erc20": "^3.0.5",
"@0x/contracts-erc721": "^3.0.5",
"@0x/contracts-exchange": "^3.1.1",
"@0x/contracts-exchange-libs": "^4.1.1",
"@0x/contracts-gen": "^2.0.5",
"@0x/contracts-test-utils": "^5.1.2",
"@0x/contracts-utils": "^4.2.0",
"@0x/dev-utils": "^3.1.2",
"@0x/order-utils": "^10.1.2",
"@0x/sol-compiler": "^4.0.5",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"@0x/utils": "^5.2.0",
"@0x/web3-wrapper": "^7.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -89,7 +90,7 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.3",
"@0x/base-contract": "^6.1.1",
"@0x/typescript-typings": "^5.0.1",
"ethereum-types": "^3.0.0"
},

View File

@@ -6,4 +6,5 @@
import { ContractArtifact } from 'ethereum-types';
import * as Forwarder from '../generated-artifacts/Forwarder.json';
export const artifacts = { Forwarder: Forwarder as ContractArtifact };
import * as IExchangeV2 from '../generated-artifacts/IExchangeV2.json';
export const artifacts = { Forwarder: Forwarder as ContractArtifact, IExchangeV2: IExchangeV2 as ContractArtifact };

View File

@@ -1,5 +1,5 @@
export { artifacts } from './artifacts';
export { ForwarderContract } from './wrappers';
export { ForwarderContract, IExchangeV2Contract } from './wrappers';
export { ExchangeForwarderRevertErrors } from '@0x/utils';
export {
ContractArtifact,

View File

@@ -4,3 +4,4 @@
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/forwarder';
export * from '../generated-wrappers/i_exchange_v2';

View File

@@ -7,13 +7,16 @@ import { ContractArtifact } from 'ethereum-types';
import * as Forwarder from '../test/generated-artifacts/Forwarder.json';
import * as IAssets from '../test/generated-artifacts/IAssets.json';
import * as IExchangeV2 from '../test/generated-artifacts/IExchangeV2.json';
import * as IForwarder from '../test/generated-artifacts/IForwarder.json';
import * as IForwarderCore from '../test/generated-artifacts/IForwarderCore.json';
import * as LibAssetDataTransfer from '../test/generated-artifacts/LibAssetDataTransfer.json';
import * as LibConstants from '../test/generated-artifacts/LibConstants.json';
import * as LibForwarderRichErrors from '../test/generated-artifacts/LibForwarderRichErrors.json';
import * as MixinAssets from '../test/generated-artifacts/MixinAssets.json';
import * as MixinExchangeWrapper from '../test/generated-artifacts/MixinExchangeWrapper.json';
import * as MixinForwarderCore from '../test/generated-artifacts/MixinForwarderCore.json';
import * as MixinReceiver from '../test/generated-artifacts/MixinReceiver.json';
import * as MixinWeth from '../test/generated-artifacts/MixinWeth.json';
import * as TestForwarder from '../test/generated-artifacts/TestForwarder.json';
export const artifacts = {
@@ -21,10 +24,13 @@ export const artifacts = {
MixinAssets: MixinAssets as ContractArtifact,
MixinExchangeWrapper: MixinExchangeWrapper as ContractArtifact,
MixinForwarderCore: MixinForwarderCore as ContractArtifact,
MixinReceiver: MixinReceiver as ContractArtifact,
MixinWeth: MixinWeth as ContractArtifact,
IAssets: IAssets as ContractArtifact,
IExchangeV2: IExchangeV2 as ContractArtifact,
IForwarder: IForwarder as ContractArtifact,
IForwarderCore: IForwarderCore as ContractArtifact,
LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact,
LibConstants: LibConstants as ContractArtifact,
LibForwarderRichErrors: LibForwarderRichErrors as ContractArtifact,
TestForwarder: TestForwarder as ContractArtifact,

View File

@@ -1,4 +1,11 @@
import { IAssetDataContract } from '@0x/contracts-asset-proxy';
import {
artifacts as ERC1155Artifacts,
ERC1155Events,
ERC1155MintableContract,
ERC1155TransferBatchEventArgs,
Erc1155Wrapper,
} from '@0x/contracts-erc1155';
import {
artifacts as ERC20Artifacts,
DummyERC20TokenContract,
@@ -20,11 +27,13 @@ import {
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { BigNumber, ExchangeForwarderRevertErrors, hexUtils } from '@0x/utils';
import { LogWithDecodedArgs } from 'ethereum-types';
import { artifacts } from './artifacts';
import { TestForwarderContract } from './wrappers';
blockchainTests('Supported asset type unit tests', env => {
// tslint:disable:no-unnecessary-type-assertion
blockchainTests.resets('Supported asset type unit tests', env => {
let forwarder: TestForwarderContract;
let assetDataEncoder: IAssetDataContract;
let bridgeAddress: string;
@@ -33,11 +42,15 @@ blockchainTests('Supported asset type unit tests', env => {
let erc20Token: DummyERC20TokenContract;
let erc721Token: DummyERC721TokenContract;
let erc1155Token: ERC1155MintableContract;
let erc1155Wrapper: Erc1155Wrapper;
let nftId: BigNumber;
let erc20AssetData: string;
let erc721AssetData: string;
let erc20BridgeAssetData: string;
let staticCallAssetData: string;
let multiAssetData: string;
before(async () => {
[receiver] = await env.getAccountAddressesAsync();
@@ -47,7 +60,7 @@ blockchainTests('Supported asset type unit tests', env => {
artifacts.TestForwarder,
env.provider,
env.txDefaults,
{ ...artifacts, ...ERC20Artifacts, ...ERC721Artifacts },
{ ...artifacts, ...ERC20Artifacts, ...ERC721Artifacts, ...ERC1155Artifacts },
);
erc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
@@ -70,14 +83,30 @@ blockchainTests('Supported asset type unit tests', env => {
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
);
nftId = getRandomInteger(constants.ZERO_AMOUNT, constants.MAX_UINT256);
nftId = getRandomInteger(0, constants.MAX_UINT256);
erc721AssetData = assetDataEncoder.ERC721Token(erc721Token.address, nftId).getABIEncodedTransactionData();
erc1155Token = await ERC1155MintableContract.deployFrom0xArtifactAsync(
ERC1155Artifacts.ERC1155Mintable,
env.provider,
env.txDefaults,
ERC1155Artifacts,
);
erc1155Wrapper = new Erc1155Wrapper(erc1155Token, receiver);
bridgeAddress = randomAddress();
bridgeData = hexUtils.random();
erc20BridgeAssetData = assetDataEncoder
.ERC20Bridge(erc20Token.address, bridgeAddress, bridgeData)
.getABIEncodedTransactionData();
staticCallAssetData = assetDataEncoder
.StaticCall(randomAddress(), hexUtils.random(), constants.KECCAK256_NULL)
.getABIEncodedTransactionData();
multiAssetData = assetDataEncoder
.MultiAsset([new BigNumber(1)], [erc20AssetData])
.getABIEncodedTransactionData();
});
describe('_areUnderlyingAssetsEqual', () => {
@@ -115,13 +144,64 @@ blockchainTests('Supported asset type unit tests', env => {
.callAsync();
expect(result).to.be.false();
});
it('returns false if assetData1 == assetData2 are ERC721', async () => {
it('returns true if assetData1 == assetData2 are ERC721', async () => {
const result = await forwarder.areUnderlyingAssetsEqual(erc721AssetData, erc721AssetData).callAsync();
expect(result).to.be.true();
});
it('returns false if assetData1 != assetData2 are ERC721', async () => {
const differentErc721AssetData = assetDataEncoder
.ERC721Token(randomAddress(), getRandomInteger(0, constants.MAX_UINT256))
.getABIEncodedTransactionData();
const result = await forwarder
.areUnderlyingAssetsEqual(erc721AssetData, differentErc721AssetData)
.callAsync();
expect(result).to.be.false();
});
it('returns true if assetData1 == assetData2 are StaticCall', async () => {
const result = await forwarder
.areUnderlyingAssetsEqual(staticCallAssetData, staticCallAssetData)
.callAsync();
expect(result).to.be.true();
});
it('returns false if assetData1 != assetData2 are StaticCall', async () => {
const differentStaticCallAssetData = assetDataEncoder
.StaticCall(randomAddress(), hexUtils.random(), constants.KECCAK256_NULL)
.getABIEncodedTransactionData();
const result = await forwarder
.areUnderlyingAssetsEqual(staticCallAssetData, differentStaticCallAssetData)
.callAsync();
expect(result).to.be.false();
});
it('returns false if assetData1 is ERC20 and assetData2 is MultiAsset', async () => {
const result = await forwarder.areUnderlyingAssetsEqual(erc20AssetData, multiAssetData).callAsync();
expect(result).to.be.false();
});
it('returns true if assetData1 == assetData2 are MultiAsset (single nested asset)', async () => {
const result = await forwarder.areUnderlyingAssetsEqual(multiAssetData, multiAssetData).callAsync();
expect(result).to.be.true();
});
it('returns true if assetData1 == assetData2 are MultiAsset (multiple nested assets)', async () => {
const assetData = assetDataEncoder
.MultiAsset(
[getRandomInteger(0, constants.MAX_UINT256), new BigNumber(1)],
[erc20AssetData, erc721AssetData],
)
.getABIEncodedTransactionData();
const result = await forwarder.areUnderlyingAssetsEqual(assetData, assetData).callAsync();
expect(result).to.be.true();
});
it('returns false if assetData1 != assetData2 are MultiAsset', async () => {
const differentMultiAssetData = assetDataEncoder
.MultiAsset([getRandomInteger(0, constants.MAX_UINT256)], [erc721AssetData])
.getABIEncodedTransactionData();
const result = await forwarder
.areUnderlyingAssetsEqual(multiAssetData, differentMultiAssetData)
.callAsync();
expect(result).to.be.false();
});
});
describe('_transferAssetToSender', () => {
describe('transferOut', () => {
const TRANSFER_AMOUNT = new BigNumber(1);
before(async () => {
await erc20Token
@@ -132,7 +212,7 @@ blockchainTests('Supported asset type unit tests', env => {
it('transfers an ERC20 token given ERC20 assetData', async () => {
const txReceipt = await forwarder
.transferAssetToSender(erc20AssetData, TRANSFER_AMOUNT)
.transferOut(erc20AssetData, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
verifyEventsFromLogs<ERC20TokenTransferEventArgs>(
txReceipt.logs,
@@ -142,7 +222,7 @@ blockchainTests('Supported asset type unit tests', env => {
});
it('transfers an ERC721 token given ERC721 assetData and amount == 1', async () => {
const txReceipt = await forwarder
.transferAssetToSender(erc721AssetData, TRANSFER_AMOUNT)
.transferOut(erc721AssetData, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
verifyEventsFromLogs<ERC721TokenTransferEventArgs>(
txReceipt.logs,
@@ -153,14 +233,120 @@ blockchainTests('Supported asset type unit tests', env => {
it('reverts if attempting to transfer an ERC721 token with amount != 1', async () => {
const invalidAmount = new BigNumber(2);
const tx = forwarder
.transferAssetToSender(erc721AssetData, invalidAmount)
.transferOut(erc721AssetData, invalidAmount)
.awaitTransactionSuccessAsync({ from: receiver });
const expectedError = new ExchangeForwarderRevertErrors.Erc721AmountMustEqualOneError(invalidAmount);
return expect(tx).to.revertWith(expectedError);
});
it('transfers a single ERC1155 token', async () => {
const values = [new BigNumber(1)];
const amount = new BigNumber(1);
const ids = [await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], values)];
const assetData = assetDataEncoder
.ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES)
.getABIEncodedTransactionData();
const txReceipt = await forwarder
.transferOut(assetData, amount)
.awaitTransactionSuccessAsync({ from: receiver });
verifyEventsFromLogs<ERC1155TransferBatchEventArgs>(
txReceipt.logs,
[{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values }],
ERC1155Events.TransferBatch,
);
});
it('transfers multiple ids of an ERC1155 token', async () => {
const amount = new BigNumber(1);
const ids = [
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]),
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]),
];
const values = [amount, amount];
const assetData = assetDataEncoder
.ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES)
.getABIEncodedTransactionData();
const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync();
verifyEventsFromLogs<ERC1155TransferBatchEventArgs>(
txReceipt.logs,
[{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values }],
ERC1155Events.TransferBatch,
);
});
it('scales up values when transfering ERC1155 tokens', async () => {
const amount = new BigNumber(2);
const values = [new BigNumber(1), new BigNumber(2)];
const scaledValues = values.map(value => value.times(amount));
const ids = [
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [scaledValues[0]]),
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [scaledValues[1]]),
];
const assetData = assetDataEncoder
.ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES)
.getABIEncodedTransactionData();
const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync();
verifyEventsFromLogs<ERC1155TransferBatchEventArgs>(
txReceipt.logs,
[{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values: scaledValues }],
ERC1155Events.TransferBatch,
);
});
it('transfers a single ERC20 token wrapped as MultiAsset', async () => {
const nestedAmount = new BigNumber(1337);
const erc20MultiAssetData = assetDataEncoder
.MultiAsset([nestedAmount], [erc20AssetData])
.getABIEncodedTransactionData();
const multiAssetAmount = new BigNumber(2);
const txReceipt = await forwarder
.transferOut(erc20MultiAssetData, multiAssetAmount)
.awaitTransactionSuccessAsync({ from: receiver });
verifyEventsFromLogs<ERC20TokenTransferEventArgs>(
txReceipt.logs,
[{ _from: forwarder.address, _to: receiver, _value: multiAssetAmount.times(nestedAmount) }],
ERC20TokenEvents.Transfer,
);
});
it('transfers ERC20, ERC721, and StaticCall assets wrapped as MultiAsset', async () => {
const nestedAmounts = [new BigNumber(1337), TRANSFER_AMOUNT, TRANSFER_AMOUNT];
const assortedMultiAssetData = assetDataEncoder
.MultiAsset(nestedAmounts, [erc20AssetData, erc721AssetData, staticCallAssetData])
.getABIEncodedTransactionData();
const txReceipt = await forwarder
.transferOut(assortedMultiAssetData, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
expect(txReceipt.logs.length).to.equal(2);
// tslint:disable:no-unnecessary-type-assertion
const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs<ERC20TokenTransferEventArgs>).args;
const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs<ERC721TokenTransferEventArgs>).args;
// tslint:enable:no-unnecessary-type-assertion
expect(erc20TransferEvent).to.deep.equal({
_from: forwarder.address,
_to: receiver,
_value: nestedAmounts[0],
});
expect(erc721TransferEvent).to.deep.equal({ _from: forwarder.address, _to: receiver, _tokenId: nftId });
});
it('performs nested MultiAsset transfers', async () => {
const nestedAmounts = [TRANSFER_AMOUNT, TRANSFER_AMOUNT, TRANSFER_AMOUNT];
const assortedMultiAssetData = assetDataEncoder
.MultiAsset(nestedAmounts, [multiAssetData, erc721AssetData, staticCallAssetData])
.getABIEncodedTransactionData();
const txReceipt = await forwarder
.transferOut(assortedMultiAssetData, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
expect(txReceipt.logs.length).to.equal(2);
// tslint:disable:no-unnecessary-type-assertion
const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs<ERC20TokenTransferEventArgs>).args;
const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs<ERC721TokenTransferEventArgs>).args;
// tslint:enable:no-unnecessary-type-assertion
expect(erc20TransferEvent).to.deep.equal({
_from: forwarder.address,
_to: receiver,
_value: TRANSFER_AMOUNT,
});
expect(erc721TransferEvent).to.deep.equal({ _from: forwarder.address, _to: receiver, _tokenId: nftId });
});
it('transfers an ERC20 token given ERC20Bridge assetData', async () => {
const txReceipt = await forwarder
.transferAssetToSender(erc20BridgeAssetData, TRANSFER_AMOUNT)
.transferOut(erc20BridgeAssetData, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
verifyEventsFromLogs<ERC20TokenTransferEventArgs>(
txReceipt.logs,
@@ -168,10 +354,16 @@ blockchainTests('Supported asset type unit tests', env => {
ERC20TokenEvents.Transfer,
);
});
it('noops (emits no events) for StaticCall assetData', async () => {
const txReceipt = await forwarder
.transferOut(staticCallAssetData, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
expect(txReceipt.logs.length).to.equal(0);
});
it('reverts if assetData is unsupported', async () => {
const randomBytes = hexUtils.random();
const tx = forwarder
.transferAssetToSender(randomBytes, TRANSFER_AMOUNT)
.transferOut(randomBytes, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
const expectedError = new ExchangeForwarderRevertErrors.UnsupportedAssetProxyError(
hexUtils.slice(randomBytes, 0, 4),

View File

@@ -5,12 +5,15 @@
*/
export * from '../test/generated-wrappers/forwarder';
export * from '../test/generated-wrappers/i_assets';
export * from '../test/generated-wrappers/i_exchange_v2';
export * from '../test/generated-wrappers/i_forwarder';
export * from '../test/generated-wrappers/i_forwarder_core';
export * from '../test/generated-wrappers/lib_asset_data_transfer';
export * from '../test/generated-wrappers/lib_constants';
export * from '../test/generated-wrappers/lib_forwarder_rich_errors';
export * from '../test/generated-wrappers/mixin_assets';
export * from '../test/generated-wrappers/mixin_exchange_wrapper';
export * from '../test/generated-wrappers/mixin_forwarder_core';
export * from '../test/generated-wrappers/mixin_receiver';
export * from '../test/generated-wrappers/mixin_weth';
export * from '../test/generated-wrappers/test_forwarder';

View File

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

View File

@@ -4,15 +4,19 @@
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/Forwarder.json",
"generated-artifacts/IExchangeV2.json",
"test/generated-artifacts/Forwarder.json",
"test/generated-artifacts/IAssets.json",
"test/generated-artifacts/IExchangeV2.json",
"test/generated-artifacts/IForwarder.json",
"test/generated-artifacts/IForwarderCore.json",
"test/generated-artifacts/LibAssetDataTransfer.json",
"test/generated-artifacts/LibConstants.json",
"test/generated-artifacts/LibForwarderRichErrors.json",
"test/generated-artifacts/MixinAssets.json",
"test/generated-artifacts/MixinExchangeWrapper.json",
"test/generated-artifacts/MixinForwarderCore.json",
"test/generated-artifacts/MixinReceiver.json",
"test/generated-artifacts/MixinWeth.json",
"test/generated-artifacts/TestForwarder.json"
],

View File

@@ -1,4 +1,23 @@
[
{
"timestamp": 1580811564,
"version": "4.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.1.0",
"changes": [
{
"note": "Reference functions for `matchOrders` and `matchOrdersWithMaximalFill`.",
"pr": 2437
}
],
"timestamp": 1579682890
},
{
"timestamp": 1578272714,
"version": "4.0.3",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.1.1 - _February 4, 2020_
* Dependencies updated
## v4.1.0 - _January 22, 2020_
* Reference functions for `matchOrders` and `matchOrdersWithMaximalFill`. (#2437)
## v4.0.3 - _January 6, 2020_
* Dependencies updated

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-libs",
"version": "4.0.3",
"version": "4.1.1",
"engines": {
"node": ">=6.12"
},
@@ -52,15 +52,14 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/subproviders": "^6.0.3",
"@0x/abi-gen": "^5.1.1",
"@0x/contracts-gen": "^2.0.5",
"@0x/dev-utils": "^3.1.2",
"@0x/sol-compiler": "^4.0.5",
"@0x/subproviders": "^6.0.5",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/web3-wrapper": "^7.0.3",
"@0x/web3-wrapper": "^7.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -81,12 +80,13 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.3",
"@0x/contracts-utils": "^4.0.3",
"@0x/order-utils": "^10.1.0",
"@0x/base-contract": "^6.1.1",
"@0x/contracts-test-utils": "^5.1.2",
"@0x/contracts-utils": "^4.2.0",
"@0x/order-utils": "^10.1.2",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"@0x/utils": "^5.2.0",
"ethereum-types": "^3.0.0"
},
"publishConfig": {

View File

@@ -1,6 +1,7 @@
import { orderHashUtils } from '@0x/contracts-test-utils';
import { ReferenceFunctions } from '@0x/contracts-utils';
import { FillResults, Order } from '@0x/types';
import { BigNumber, LibMathRevertErrors } from '@0x/utils';
import { FillResults, MatchedFillResults, Order } from '@0x/types';
import { BigNumber, ExchangeRevertErrors, LibMathRevertErrors } from '@0x/utils';
const { safeAdd, safeSub, safeMul, safeDiv } = ReferenceFunctions;
@@ -114,6 +115,119 @@ export function calculateFillResults(
};
}
/**
* Calculates amounts filled and fees paid by maker and taker.
*/
export function calculateMatchResults(
leftOrder: Order,
rightOrder: Order,
protocolFeeMultiplier: BigNumber,
gasPrice: BigNumber,
withMaximalFill: boolean = false,
): MatchedFillResults {
// Initialize empty fill results.
const leftFillResults: FillResults = {
makerAssetFilledAmount: new BigNumber(0),
takerAssetFilledAmount: new BigNumber(0),
makerFeePaid: new BigNumber(0),
takerFeePaid: new BigNumber(0),
protocolFeePaid: new BigNumber(0),
};
const rightFillResults: FillResults = {
makerAssetFilledAmount: new BigNumber(0),
takerAssetFilledAmount: new BigNumber(0),
makerFeePaid: new BigNumber(0),
takerFeePaid: new BigNumber(0),
protocolFeePaid: new BigNumber(0),
};
let profitInLeftMakerAsset = new BigNumber(0);
let profitInRightMakerAsset = new BigNumber(0);
// Assert matchable
if (
leftOrder.makerAssetAmount
.times(rightOrder.makerAssetAmount)
.lt(leftOrder.takerAssetAmount.times(rightOrder.takerAssetAmount))
) {
throw new ExchangeRevertErrors.NegativeSpreadError(
orderHashUtils.getOrderHashHex(leftOrder),
orderHashUtils.getOrderHashHex(rightOrder),
);
}
// Asset Transfer Amounts
if (leftOrder.takerAssetAmount.gt(rightOrder.makerAssetAmount)) {
leftFillResults.makerAssetFilledAmount = safeGetPartialAmountFloor(
leftOrder.makerAssetAmount,
leftOrder.takerAssetAmount,
rightOrder.makerAssetAmount,
);
leftFillResults.takerAssetFilledAmount = rightOrder.makerAssetAmount;
rightFillResults.makerAssetFilledAmount = rightOrder.makerAssetAmount;
rightFillResults.takerAssetFilledAmount = rightOrder.takerAssetAmount;
} else if (withMaximalFill && leftOrder.makerAssetAmount.lt(rightOrder.takerAssetAmount)) {
leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount;
leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount;
rightFillResults.makerAssetFilledAmount = safeGetPartialAmountFloor(
rightOrder.makerAssetAmount,
rightOrder.takerAssetAmount,
leftOrder.makerAssetAmount,
);
rightFillResults.takerAssetFilledAmount = leftOrder.makerAssetAmount;
} else if (!withMaximalFill && leftOrder.takerAssetAmount.lt(rightOrder.makerAssetAmount)) {
leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount;
leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount;
rightFillResults.makerAssetFilledAmount = leftOrder.takerAssetAmount;
rightFillResults.takerAssetFilledAmount = safeGetPartialAmountCeil(
rightOrder.takerAssetAmount,
rightOrder.makerAssetAmount,
leftOrder.takerAssetAmount,
);
} else {
leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount;
leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount;
rightFillResults.makerAssetFilledAmount = rightOrder.makerAssetAmount;
rightFillResults.takerAssetFilledAmount = rightOrder.takerAssetAmount;
}
// Profit
profitInLeftMakerAsset = leftFillResults.makerAssetFilledAmount.minus(rightFillResults.makerAssetFilledAmount);
profitInRightMakerAsset = rightFillResults.makerAssetFilledAmount.minus(leftFillResults.makerAssetFilledAmount);
// Fees
leftFillResults.makerFeePaid = safeGetPartialAmountFloor(
leftFillResults.makerAssetFilledAmount,
leftOrder.makerAssetAmount,
leftOrder.makerFee,
);
leftFillResults.takerFeePaid = safeGetPartialAmountFloor(
leftFillResults.takerAssetFilledAmount,
leftOrder.takerAssetAmount,
leftOrder.takerFee,
);
rightFillResults.makerFeePaid = safeGetPartialAmountFloor(
rightFillResults.makerAssetFilledAmount,
rightOrder.makerAssetAmount,
rightOrder.makerFee,
);
rightFillResults.takerFeePaid = safeGetPartialAmountFloor(
rightFillResults.takerAssetFilledAmount,
rightOrder.takerAssetAmount,
rightOrder.takerFee,
);
// Protocol Fee
leftFillResults.protocolFeePaid = safeMul(protocolFeeMultiplier, gasPrice);
rightFillResults.protocolFeePaid = safeMul(protocolFeeMultiplier, gasPrice);
return {
left: leftFillResults,
right: rightFillResults,
profitInLeftMakerAsset,
profitInRightMakerAsset,
};
}
export const LibFractions = {
add: (n1: BigNumber, d1: BigNumber, n2: BigNumber, d2: BigNumber): [BigNumber, BigNumber] => {
if (n1.isZero()) {

View File

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

View File

@@ -1,4 +1,23 @@
[
{
"timestamp": 1580811564,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [
{
"note": "Uses updated event decoding to properly decodes arrays and objects.",
"pr": 2443
}
],
"timestamp": 1579682890
},
{
"timestamp": 1578272714,
"version": "3.0.3",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.1 - _February 4, 2020_
* Dependencies updated
## v3.1.0 - _January 22, 2020_
* Uses updated event decoding to properly decodes arrays and objects. (#2443)
## v3.0.3 - _January 6, 2020_
* Dependencies updated

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange",
"version": "3.0.3",
"version": "3.1.1",
"engines": {
"node": ">=6.12"
},
@@ -52,21 +52,21 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-asset-proxy": "^3.1.0",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-multisig": "^4.0.3",
"@0x/contracts-staking": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/abi-gen": "^5.1.1",
"@0x/contracts-asset-proxy": "^3.1.2",
"@0x/contracts-exchange-libs": "^4.1.1",
"@0x/contracts-gen": "^2.0.5",
"@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/dev-utils": "^3.1.2",
"@0x/sol-compiler": "^4.0.5",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/web3-wrapper": "^7.0.3",
"@0x/web3-wrapper": "^7.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -88,13 +88,13 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.3",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc1155": "^2.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-erc721": "^3.0.3",
"@0x/order-utils": "^10.1.0",
"@0x/utils": "^5.1.2",
"@0x/base-contract": "^6.1.1",
"@0x/contracts-dev-utils": "^1.0.5",
"@0x/contracts-erc1155": "^2.0.5",
"@0x/contracts-erc20": "^3.0.5",
"@0x/contracts-erc721": "^3.0.5",
"@0x/order-utils": "^10.1.2",
"@0x/utils": "^5.2.0",
"lodash": "^4.17.11"
},
"publishConfig": {

View File

@@ -121,22 +121,21 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
}
}
function assertSameOrderFromEvent(actual: any[], expected: Order): void {
expect(actual.length === 14);
expect(actual[0].toLowerCase()).to.be.eq(expected.makerAddress);
expect(actual[1].toLowerCase()).to.be.eq(expected.takerAddress);
expect(actual[2].toLowerCase()).to.be.eq(expected.feeRecipientAddress);
expect(actual[3].toLowerCase()).to.be.eq(expected.senderAddress);
expect(actual[4]).to.be.bignumber.eq(expected.makerAssetAmount);
expect(actual[5]).to.be.bignumber.eq(expected.takerAssetAmount);
expect(actual[6]).to.be.bignumber.eq(expected.makerFee);
expect(actual[7]).to.be.bignumber.eq(expected.takerFee);
expect(actual[8]).to.be.bignumber.eq(expected.expirationTimeSeconds);
expect(actual[9]).to.be.bignumber.eq(expected.salt);
expect(actual[10]).to.be.eq(expected.makerAssetData);
expect(actual[11]).to.be.eq(expected.takerAssetData);
expect(actual[12]).to.be.eq(expected.makerFeeAssetData);
expect(actual[13]).to.be.eq(expected.takerFeeAssetData);
function assertSameOrderFromEvent(actual: any, expected: Order): void {
expect(actual.makerAddress).to.be.eq(expected.makerAddress);
expect(actual.takerAddress).to.be.eq(expected.takerAddress);
expect(actual.feeRecipientAddress).to.be.eq(expected.feeRecipientAddress);
expect(actual.senderAddress).to.be.eq(expected.senderAddress);
expect(actual.makerAssetAmount).to.bignumber.eq(expected.makerAssetAmount);
expect(actual.takerAssetAmount).to.bignumber.eq(expected.takerAssetAmount);
expect(actual.makerFee).to.bignumber.eq(expected.makerFee);
expect(actual.takerFee).to.bignumber.eq(expected.takerFee);
expect(actual.expirationTimeSeconds).to.bignumber.eq(expected.expirationTimeSeconds);
expect(actual.salt).to.bignumber.eq(expected.salt);
expect(actual.makerAssetData).to.eq(expected.makerAssetData);
expect(actual.takerAssetData).to.eq(expected.takerAssetData);
expect(actual.makerFeeAssetData).to.eq(expected.makerFeeAssetData);
expect(actual.takerFeeAssetData).to.eq(expected.takerFeeAssetData);
}
describe('fillOrKillOrder', () => {

View File

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

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1580811564,
"version": "5.1.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "5.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1578272714,
"version": "5.1.2",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.1.4 - _February 4, 2020_
* Dependencies updated
## v5.1.3 - _January 22, 2020_
* Dependencies updated
## v5.1.2 - _January 6, 2020_
* Dependencies updated

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-extensions",
"version": "5.1.2",
"version": "5.1.4",
"engines": {
"node": ">=6.12"
},
@@ -52,24 +52,24 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-asset-proxy": "^3.1.0",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-erc721": "^3.0.3",
"@0x/contracts-exchange": "^3.0.3",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/order-utils": "^10.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/abi-gen": "^5.1.1",
"@0x/contracts-asset-proxy": "^3.1.2",
"@0x/contracts-dev-utils": "^1.0.5",
"@0x/contracts-erc20": "^3.0.5",
"@0x/contracts-erc721": "^3.0.5",
"@0x/contracts-exchange": "^3.1.1",
"@0x/contracts-exchange-libs": "^4.1.1",
"@0x/contracts-gen": "^2.0.5",
"@0x/contracts-test-utils": "^5.1.2",
"@0x/contracts-utils": "^4.2.0",
"@0x/dev-utils": "^3.1.2",
"@0x/order-utils": "^10.1.2",
"@0x/sol-compiler": "^4.0.5",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.1",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"@0x/utils": "^5.2.0",
"@0x/web3-wrapper": "^7.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -91,7 +91,7 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.3",
"@0x/base-contract": "^6.1.1",
"@0x/typescript-typings": "^5.0.1",
"ethereum-types": "^3.0.0"
},

View File

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

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1580811564,
"version": "2.2.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579744659,
"version": "2.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.2.0",
"changes": [
{
"note": "Add mainnet contract wrapper `callAsync()` revert behavior tests.",
"pr": 2433
},
{
"note": "Fuzz tests for `matchOrders` and `matchOrdersWithMaximalFill`.",
"pr": 2437
},
{
"note": "Add various negative assertions for fuzz tests",
"pr": 2431
}
],
"timestamp": 1579682890
},
{
"version": "2.1.0",
"changes": [
@@ -9,6 +45,10 @@
{
"note": "Add aggregator mainnet tests.",
"pr": 2407
},
{
"note": "Add fuzz tests for Exchange signature validation.",
"pr": 2425
}
],
"timestamp": 1578272714

View File

@@ -5,10 +5,25 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.2.2 - _February 4, 2020_
* Dependencies updated
## v2.2.1 - _January 23, 2020_
* Dependencies updated
## v2.2.0 - _January 22, 2020_
* Add mainnet contract wrapper `callAsync()` revert behavior tests. (#2433)
* Fuzz tests for `matchOrders` and `matchOrdersWithMaximalFill`. (#2437)
* Add various negative assertions for fuzz tests (#2431)
## v2.1.0 - _January 6, 2020_
* Integration tests for DydxBridge with (i) Exchange v3 and (ii) Mainnet dYdX SoloMargin contract. (#2401)
* Add aggregator mainnet tests. (#2407)
* Add fuzz tests for Exchange signature validation. (#2425)
## v2.0.2 - _December 17, 2019_

View File

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

View File

@@ -0,0 +1,60 @@
/*
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;
// solhint-disable no-empty-blocks
contract TestContractWrapper {
uint256 constant public VALID_RETURN_VALUE = 0xf984f922a56ea9a20a32a32f0f60f2d216ff0c0a0d16c986a97a7f1897a6613b;
function throwStringRevert() external returns (uint256) {
revert("ERROR");
}
function throwEmptyRevert() external returns (uint256) {
revert();
}
function throwInvalidOpcode() external returns (uint256) {
assembly {
invalid()
}
}
function returnForcedEmpty() external returns (uint256) {
assembly {
return(0x60, 0)
}
}
function returnTruncated() external returns (uint256) {
uint256 v = VALID_RETURN_VALUE;
assembly {
mstore(0x0, v)
return(0x0, 16)
}
}
function returnEmpty() external { }
function returnValid() external returns (uint256) {
return VALID_RETURN_VALUE;
}
}

View File

@@ -0,0 +1,53 @@
/*
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.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibEIP1271.sol";
contract TestSignatureValidationWallet is
LibEIP1271
{
bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381;
// Callback used by `EIP1271Wallet` and `Validator` signature types.
function isValidSignature(
bytes memory,
bytes memory
)
public
pure
returns (bytes4 magicValue)
{
return EIP1271_MAGIC_VALUE;
}
// Callback used by `Wallet` signature type.
function isValidSignature(
bytes32,
bytes memory
)
public
pure
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

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