Compare commits

..

195 Commits

Author SHA1 Message Date
Alex Browne
7c8a7a2420 Updated CHANGELOGS 2018-08-13 18:34:37 -07:00
Alex Browne
3b0fa1aa87 fix(0x.js, order-utils): Fix CHANGELOG.json versions 2018-08-13 18:06:27 -07:00
Alex Browne
283175df98 Run publish/installation tests in CircleCI (#951)
feat(monorepo-scripts): Run publish tests in CircleCI
2018-08-13 16:49:50 -07:00
Fabio Berger
aeb368a1d9 Merge pull request #932 from 0xProject/fix-ganache-fork
Fix ganache fork
2018-08-13 19:45:01 -04:00
Jacob Evans
e51deb93ee Merge pull request #914 from 0xProject/feature/0x.js/ec-signature-string
0x.js Return signature as a hex encoded string
2018-08-14 09:36:11 +10:00
Jacob Evans
a351757493 Update version numbers.
Add source for Metamask future fix.
Consolidate switch statement to one return
2018-08-14 09:18:13 +10:00
Francesco Agosti
0025c6640b Merge pull request #958 from 0xProject/feature/sra-api/camel-case-everything
[sra-api] Enforce camelCase for all parameters and other changes.
2018-08-13 15:12:01 -07:00
Alex Browne
25a8554be1 fix(sol-compiler, sol-resolver): Bug where sol-resolver tried to read a directory (#961)
fix(sol-compiler, sol-resolver): Fix bug where sol-resolver tried to read a directory
2018-08-13 14:17:05 -07:00
Fabio Berger
cd76c129da Merge pull request #955 from feuGeneA/patch-6
[PR template] a to-do list should be in the imperative mood
2018-08-13 16:46:34 -04:00
Fabio Berger
7340338626 Merge pull request #938 from 0xProject/sol-cov-fixes
Sol cov fixes
2018-08-13 16:40:46 -04:00
Fabio Berger
9d3c287918 Merge branch 'sol-cov-fixes' of github.com:0xProject/0x-monorepo into sol-cov-fixes
* 'sol-cov-fixes' of github.com:0xProject/0x-monorepo: (49 commits)
  Add @return comments
  Import marshaller directly
  Update comment about ethers checksummed address behavior
  Add packages/coverage/.gitkeep file
  Update CI config and package.json to run @0xproject/utils tests on CI
  Update remaining CHANGELOG.json files
  Change amir picture
  Update CHANGELOG.json for contract-wrappers
  Update ethers typings for TypeScript 2.9.2
  Update CHANGELOG.json for base-contract
  Move some ethers-related types to typescript-typings/ethers
  Apply prettier
  Add strictArgumentEncodingCheck to BaseContract and use it in contract templates
  fix(monorepo-scripts): Fix typo in git tag command
  feat(monorepo-scripts): Add confirmation prompt before publishing
  fix comments and styling for MixinSignatureValidator
  Update TypeScript to version 2.9.2
  Use asm for hashEIP712Message, increment free memory pointer after asm hashing functions
  Fix comments, styling, and optimize hashOrder
  Remove assertion comments
  ...
2018-08-13 13:01:32 -07:00
Fabio Berger
c2b5fe3d84 Remove test for unknown prop now that we are allowing additional props fro txData 2018-08-13 13:01:10 -07:00
fragosti
5ef84d61fa Ignore api.json in prettier 2018-08-13 12:58:15 -07:00
fragosti
58321a36dc apply prettier 2018-08-13 11:45:13 -07:00
Jacob Evans
ca4905c343 Rename from SignerProviderType.EthSign to SignerType.Default 2018-08-11 18:27:21 +10:00
fragosti
b6d793aec4 Enforce camelCase for all parameters and change the way the site is deployed and hosted 2018-08-10 15:56:47 -07:00
F. Eugene Aumson
83fb9df63d a to-do list should be in the imperative mood 2018-08-10 00:34:31 -07:00
Amir Bandeali
083319786f Merge pull request #948 from 0xProject/feature/contracts/forwarderFoK
[contracts] Make marketBuy functions revert if entire amount not filled
2018-08-09 17:22:56 -07:00
Francesco Agosti
719699eb30 Merge pull request #916 from 0xProject/feature/sra/add-sra-package
Add the sra-api package (OpenAPI Spec)
2018-08-09 17:02:43 -07:00
fragosti
889ec81ff3 Fix order-watcher json-schemas 2018-08-09 16:43:16 -07:00
fragosti
2f66f26048 Fix linting issues 2018-08-09 16:41:43 -07:00
fragosti
713f285f37 fix contract-wrappers json-schemas 2018-08-09 16:22:20 -07:00
fragosti
938a99f435 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/sra/add-sra-package 2018-08-09 15:57:12 -07:00
Alex Browne
f97ec000e1 Merge pull request #949 from 0xProject/fix/update-dependencies
fix: Update dependencies
2018-08-09 14:22:16 -07:00
Amir Bandeali
1b5c5e7a3b Change withdrawERC20 => withdrawAsset, reuse transfer logic 2018-08-09 14:07:27 -07:00
fragosti
c804e2230d Update Clays linkedin 2018-08-09 12:25:26 -07:00
fragosti
3f610d4865 Merge https://github.com/0xProject/0x-monorepo into development 2018-08-09 12:15:30 -07:00
fragosti
8404e0e73f Add clay to website 2018-08-09 12:15:18 -07:00
fragosti
b2c666bb1f Apply prettier 2018-08-09 11:42:05 -07:00
Alex Browne
f3761af567 fix: Update dependencies 2018-08-09 11:35:54 -07:00
Amir Bandeali
b9d8d2d5e3 Make marketBuy functions revert if entire amount not filled 2018-08-09 11:26:32 -07:00
Amir Bandeali
b60a74c8bc Merge pull request #941 from 0xProject/feature/contracts/returnValuesTests
[contracts] Test fillOrder return values and abiEncodeFillOrder
2018-08-09 10:39:14 -07:00
fragosti
0113ecee96 Change scripts folder to build_scripts 2018-08-09 10:13:37 -07:00
fragosti
eb20e86947 Force case change in file 2018-08-09 09:39:29 -07:00
Leonid Logvinov
15e15f994a Merge branch 'development' into sol-cov-fixes 2018-08-09 17:03:41 +02:00
Leonid Logvinov
d44ff6a915 Add @return comments 2018-08-09 17:02:13 +02:00
Leonid Logvinov
68605ca261 Import marshaller directly 2018-08-09 17:00:05 +02:00
Jacob Evans
5d4dd406f2 Update Changelogs. Rebased from development 2018-08-09 12:05:17 +10:00
Jacob Evans
9dd6ba7825 Update jsdoc 2018-08-09 12:02:17 +10:00
Jacob Evans
45e9fbe8f9 Introduce SignerProviderType
This allows the developer to indicate the nuanced signer provider. Some have different implementations (trezor, ledger) and others have different implementations (metamask). Breaking the abstraction of eth_sign. EthSign assumes a spec compliant implementation and can be used as a default
2018-08-09 12:02:12 +10:00
Alex Browne
53713188fe Merge pull request #915 from 0xProject/feature/encode-decode-checks
Add strictArgumentEncodingCheck to BaseContract and use it in contract templates
2018-08-08 18:28:15 -07:00
Alex Browne
c4c37cafa0 Update comment about ethers checksummed address behavior 2018-08-08 17:58:04 -07:00
Alex Browne
5b7774f9d0 Add packages/coverage/.gitkeep file 2018-08-08 17:33:20 -07:00
Alex Browne
ca7d8a8940 Update CI config and package.json to run @0xproject/utils tests on CI 2018-08-08 16:47:36 -07:00
Alex Browne
762bbe9bcd Update remaining CHANGELOG.json files 2018-08-08 16:44:52 -07:00
fragosti
03fb73d1d2 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into development 2018-08-08 15:50:59 -07:00
Amir Bandeali
d10e2652ae Revert incrementing memory ptr in dispatchTransferFrom 2018-08-08 15:44:43 -07:00
Amir Bandeali
9a5d7b7635 Test abiEncodeFillOrder as part of combinatorial follOrder tests 2018-08-08 15:44:43 -07:00
Amir Bandeali
1fb3da6b53 Increment free memory pointer for internal Exchange functions that use asm 2018-08-08 15:44:43 -07:00
Amir Bandeali
970bef717e Add return values to combinatorial fillOrder tests 2018-08-08 15:44:43 -07:00
fragosti
2a85f79040 Change amir picture 2018-08-08 15:42:09 -07:00
Amir Bandeali
651a468b44 Merge pull request #946 from 0xProject/fix/contracts/signatureValidatorComments
[contracts] Fix comments and styling for MixinSignatureValidator
2018-08-08 15:35:34 -07:00
fragosti
5e8ad0aef4 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/sra/add-sra-package 2018-08-08 15:12:10 -07:00
Alex Browne
44d909c0c7 Update CHANGELOG.json for contract-wrappers 2018-08-08 14:54:35 -07:00
Alex Browne
44b01f2069 Update ethers typings for TypeScript 2.9.2 2018-08-08 14:52:05 -07:00
fragosti
d7d51791a6 Remove md hints because the static site cannot handle them 2018-08-08 14:50:06 -07:00
fragosti
9e3fe7092b Add section about json-schemas and sra report 2018-08-08 14:47:43 -07:00
fragosti
083d42c8f7 Fix links in markdown 2018-08-08 14:36:38 -07:00
fragosti
6121a6d2bf Add to changelog and fix OrderBook typo 2018-08-08 14:28:09 -07:00
Alex Browne
09af23f950 Update CHANGELOG.json for base-contract 2018-08-08 14:27:30 -07:00
Alex Browne
52e094addc Move some ethers-related types to typescript-typings/ethers 2018-08-08 14:27:30 -07:00
Alex Browne
6a6739ebbe Apply prettier 2018-08-08 14:27:30 -07:00
Alex Browne
6a5965d73b Add strictArgumentEncodingCheck to BaseContract and use it in contract templates 2018-08-08 14:27:30 -07:00
Alex Browne
19cda0eb03 Merge pull request #947 from 0xProject/feature/confirm-before-publish
Add confirmation prompt before publishing
2018-08-08 14:23:52 -07:00
fragosti
cc67c0df51 Correct orderbook typo 2018-08-08 14:18:24 -07:00
fragosti
76b91cbcda Enforce that error code are ints not number 2018-08-08 14:16:59 -07:00
Alex Browne
13f0d27f7c Merge pull request #945 from 0xProject/fix/typescript-2.9.2
Update TypeScript to version 2.9.2
2018-08-08 14:12:18 -07:00
Alex Browne
5ccf41c566 fix(monorepo-scripts): Fix typo in git tag command 2018-08-08 14:01:57 -07:00
Alex Browne
797fd38e00 feat(monorepo-scripts): Add confirmation prompt before publishing 2018-08-08 14:01:12 -07:00
fragosti
9aacceb0e4 Remove tests directory, use swagger api, make json api compliant 2018-08-08 14:00:50 -07:00
Amir Bandeali
68fb1bf376 fix comments and styling for MixinSignatureValidator 2018-08-08 13:58:29 -07:00
Amir Bandeali
a6ccfaf9ca Merge pull request #925 from 0xProject/refactor/contracts/hashing
[contracts] Fix comments, styling and small optimization for hashOrder
2018-08-08 13:48:31 -07:00
fragosti
c9e1b7c5dc Change remainingFillableAmount to metaData 2018-08-08 11:57:16 -07:00
Alex Browne
6e2e658162 Update TypeScript to version 2.9.2 2018-08-08 11:27:38 -07:00
Amir Bandeali
149c07dfd2 Use asm for hashEIP712Message, increment free memory pointer after asm hashing functions 2018-08-08 11:15:38 -07:00
fragosti
853b5aa38b Change some static side configs 2018-08-07 18:18:37 -07:00
fragosti
4e30bc3e16 Add POST order endpoint 2018-08-07 17:58:38 -07:00
fragosti
95b656f360 Add GET fee_recipients 2018-08-07 17:42:52 -07:00
fragosti
b0a7db81cb Add GET order_config 2018-08-07 16:52:34 -07:00
fragosti
e6c91493f2 token_pairs -> asset_pairs 2018-08-07 16:26:25 -07:00
fragosti
3771df728c Add GET OrderBook endpoint 2018-08-07 16:24:31 -07:00
fragosti
f6dbc23995 Add GET order endpoint spec 2018-08-07 16:10:59 -07:00
fragosti
f36a43a83f Add orders endpoint 2018-08-07 15:39:33 -07:00
fragosti
f4c2fabbf8 Minor refactoring 2018-08-07 15:03:52 -07:00
Amir Bandeali
3d6cf50364 Fix comments, styling, and optimize hashOrder 2018-08-07 14:34:28 -07:00
fragosti
0a616ad3b8 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/sra/add-sra-package 2018-08-07 13:52:53 -07:00
fragosti
57a4429123 Add discharge config and deploy 2018-08-07 13:50:56 -07:00
fragosti
3b542bf356 Add static site build 2018-08-07 13:36:59 -07:00
fragosti
be472b61e7 Add markdown section 2018-08-07 13:22:11 -07:00
Brandon Millman
8199e87943 Merge pull request #937 from 0xProject/feature/contract-wrappers/forwarder-estimation-utils
Add marketUtils object for assisting with market buy calculations
2018-08-06 16:36:32 -04:00
Brandon Millman
35201af4b1 Remove assertion comments 2018-08-06 16:35:49 -04:00
Brandon Millman
0bc775cdb8 Remove 0x test case from hexSchema test 2018-08-05 21:02:10 -04:00
Brandon Millman
2273798df9 Update CHANGELOGs 2018-08-05 20:58:57 -04:00
Brandon Millman
7d0bec9b2a Add some test cases that stress slippageBufferAmount param 2018-08-05 20:54:29 -04:00
Brandon Millman
8382161f75 Add tests for findFeeOrdersThatCoverFeesForTargetOrders 2018-08-05 20:48:56 -04:00
Brandon Millman
bc5f8e52de Change orderStates param name to remaingFillableMakerAssetAmounts 2018-08-05 18:33:52 -04:00
Brandon Millman
09c0fc94fc Implement first round of tests for findOrdersThatCoverMakerAssetFillAmount 2018-08-05 18:33:52 -04:00
Brandon Millman
e5d65b585a Update hex schema to match 0x 2018-08-05 18:33:52 -04:00
Brandon Millman
d9933237a0 Move helper functions into order-utils 2018-08-05 18:33:52 -04:00
Brandon Millman
a016747c36 Add findFeeOrdersThatCoverFeesForTargetOrders to ForwarderWrapper 2018-08-05 18:33:52 -04:00
Brandon Millman
1c06380ef5 Add findOrdersThatCoverMakerAssetFillAmount static method on ForwarderWrapper 2018-08-05 18:33:52 -04:00
Brandon Millman
47fef1f8ff Merge pull request #936 from 0xProject/feature/contract-wrappers/forwader-optimizations
ForwarderWrapper order optimizations
2018-08-05 17:47:42 -04:00
Brandon Millman
3cb955c136 Move CreateOrderOpts into shared types 2018-08-05 17:15:58 -04:00
Brandon Millman
47673ba4bb Update createFactory to accept one createOrderOpts param to encompass all optional params 2018-08-05 16:54:35 -04:00
Brandon Millman
3865a081a0 Prettier 2018-08-03 16:46:55 -04:00
Brandon Millman
d00ee5df0d Fix CHANGELOGs 2018-08-03 16:04:59 -04:00
Brandon Millman
4f381ca1d9 Update orderFactory interface 2018-08-03 16:04:47 -04:00
Leonid Logvinov
bb4d15005a Add comments 2018-08-03 16:45:26 +02:00
Leonid Logvinov
477c3dc4f6 Add PR numbers 2018-08-03 16:28:00 +02:00
Leonid Logvinov
81f689e693 Add sol-cov CHANGELOG 2018-08-03 13:57:19 +02:00
Leonid Logvinov
e80fa6e311 Read truffle compiler config from truffle.js and assert that the passed solidity version matches the one in artifacts 2018-08-03 13:42:47 +02:00
Leonid Logvinov
c94168981c Use CallDataRPC in subprovider 2018-08-03 13:42:05 +02:00
Leonid Logvinov
749ec0cefe Add a TODO for failed transactions 2018-08-03 13:38:40 +02:00
Leonid Logvinov
bd488020df Export RPC data types from web3-wrapper 2018-08-03 13:36:16 +02:00
Leonid Logvinov
ab398751e1 Alow additional properties in txData json-schema 2018-08-03 13:34:40 +02:00
Leonid Logvinov
74d5f2f0b9 Export marshaller from web3-wrapper 2018-08-03 13:32:45 +02:00
fragosti
260640feed Refactor using some utility methods 2018-08-02 20:19:50 -07:00
fragosti
36e7cb16aa Add errors and headers 2018-08-02 18:24:24 -07:00
fragosti
0390a5ecbf Limit error codes with ranges 2018-08-02 18:08:36 -07:00
Brandon Millman
82092ab50a Rename to calldata utils 2018-08-02 16:03:19 -07:00
Brandon Millman
c3e6be7956 Add missing PR numbers 2018-08-02 15:53:02 -07:00
fragosti
1ce6579c3a Create asset_pairs SRA endpoint (and establish conventions) 2018-08-02 15:25:40 -07:00
fragosti
afc5c2616a Enforce stronger naming convention for json schema ids 2018-08-02 11:57:23 -07:00
Brandon Millman
6e74896620 CHANGELOG 2018-08-01 20:49:10 -07:00
Brandon Millman
30c6fe08ec Add tests 2018-08-01 20:47:59 -07:00
Brandon Millman
7c864b81e0 Add createOrder with no signing to orderFactory 2018-08-01 20:47:59 -07:00
Brandon Millman
4f006fdc5c Create marketBuyOrdersOptimizations 2018-08-01 20:23:44 -07:00
Brandon Millman
9f7f61085c Update contract-wrappers CHANGELOG.json 2018-08-01 15:29:47 -07:00
Brandon Millman
2414b47a30 Merge pull request #934 from 0xProject/feature/contract-wrappers/forwader
Initial forwarder contract wrapper
2018-08-01 15:26:45 -07:00
fragosti
f8a252d142 All schema tests padding 2018-08-01 13:55:16 -07:00
fragosti
962d6e71b6 update orders channel subscribe schema 2018-08-01 13:52:40 -07:00
fragosti
48aaf22855 Update order book schema test 2018-08-01 13:34:10 -07:00
fragosti
8351f5998a Add relayerApiOrdersResponseTest 2018-08-01 13:27:01 -07:00
fragosti
86eafeb826 Add tests for asset pair endpoint 2018-08-01 11:44:59 -07:00
fragosti
63e088730a Group all standard relayer api tests together 2018-07-31 17:46:57 -07:00
fragosti
a78d35f84e Add test for relayerApiOrderSchema 2018-07-31 17:22:26 -07:00
fragosti
63e869f6d0 Add paginated collection test case 2018-07-31 17:04:22 -07:00
fragosti
4aff9515d8 Get schema tests running (not crashiing) 2018-07-31 16:37:51 -07:00
Leonid Logvinov
6f0daa5463 Add the CHANGELOG entry for #909 2018-07-31 15:28:17 +02:00
Leonid Logvinov
a658aaaf30 Merge pull request #909 from joincivil/ritave/resolver-check-dirs
Fixed the relative resolver not checking if the file can be read in the
2018-07-31 14:49:50 +02:00
Leonid Logvinov
37590d5f5e Merge branch 'development' into ritave/resolver-check-dirs 2018-07-31 14:47:51 +02:00
Brandon Millman
ca1f926d6d Clarify ethAmount is in wei 2018-07-31 00:26:53 -07:00
Brandon Millman
5d44a67e62 Update forwarder_wrapper_test 2018-07-31 00:11:29 -07:00
Brandon Millman
8ed3d59f96 Add more assertions 2018-07-31 00:11:29 -07:00
Brandon Millman
bc93ff0cb5 Write initial test for forwarder_wrapper 2018-07-31 00:11:29 -07:00
Brandon Millman
44498f2263 Fix spelling error in exchange wrapper tests 2018-07-31 00:11:29 -07:00
Brandon Millman
045751a430 Add getOrdersInfo to exchange_wrapper 2018-07-31 00:11:28 -07:00
fragosti
162fe797fc Update schemas export 2018-07-30 17:53:01 -07:00
fragosti
e671563f1e Update json-schemas for SRA v1 2018-07-30 17:16:14 -07:00
Brandon Millman
a7238d0fdb Implement initial forwarder wrapper 2018-07-30 13:58:19 -07:00
Fabio Berger
2a899f5295 Move to dep 2018-07-30 22:42:22 +02:00
Fabio Berger
b7cd84fad6 Remove outdated parts of Dockerfile 2018-07-30 22:42:05 +02:00
Fabio Berger
36b6da7c4f Fix github dep to point to branch 2018-07-30 22:41:51 +02:00
Brandon Millman
02eb575813 Merge pull request #931 from 0xProject/feature/website/meta-tags
Add MetaTags component for easily adding customizable meta tags for a new page
2018-07-30 13:28:09 -07:00
Brandon Millman
ca8a6665ba Add back tags in html 2018-07-30 13:27:27 -07:00
Brandon Millman
2ecf7a3349 Fix jobs page overflow issue 2018-07-30 00:58:30 -07:00
Brandon Millman
5283dcce2e Create MetaTags component 2018-07-30 00:48:39 -07:00
Francesco Agosti
48e538f5c7 Merge pull request #910 from 0xProject/feature/website/upgrade-allowance-toggles-to-locks-and-checks
[website] Use new designs with tooltips for allowance toggles
2018-07-27 12:02:29 -07:00
fragosti
c851c37630 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/website/upgrade-allowance-toggles-to-locks-and-checks 2018-07-27 11:51:30 -07:00
fragosti
a0d7b1efa5 Remove unused variable 2018-07-27 11:49:06 -07:00
fragosti
1a06e6b305 Add loading state for initial load and other PR feedback 2018-07-27 11:48:04 -07:00
fragosti
43d7045a5b Add scripts 2018-07-27 10:19:20 -07:00
Olaf Tomalka
9199a56b7a Added fix to CHANGELOG 2018-07-27 15:20:24 +02:00
Fabio Berger
44d1be27e6 Add note about needing Yarn 1.6 to README 2018-07-27 12:22:43 +02:00
Alex Browne
554d5f97df Add combinatorial tests for internal Exchange functions (#807)
* WIP add combinatorial tests for internal Exchange functions

* Change combinitorial testing strategy based on feedback

* Check value of filled[orderHash] in updateFilledState tests

* Add combinatorial tests for addFillResults

* Add combinatorial tests for getPartialAmount

* Implement generic `testWithReferenceFuncAsync`

* Implement generic `testCombinatoriallyWithReferenceFuncAsync`

* Add combinatorial tests for isRoundingError

* Add combinatorial tests for calculateFillResults

* Add support for Geth in internal contract tests

* Fix contract artifacts

* Change DECIMAL_PLACES to 78 and add a note.

* Document new functions in utils

* Optimize tests by only reseting state when needed

* Rename/move some files

* Print parameter names on failure in testWithReferenceFuncAsync

* Add to changelog for utils package

* Appease various linters

* Rename some more things related to FillOrderCombinatorialUtils

* Remove .only from test/exchange/internal.ts

* Remove old test for isRoundingError and getPartialAmount

* Appease linters again

* Remove old todos

* Fix typos, add comments, rename some things

* Re-add some LibMath tests

* Update contract internal tests to use new SafeMath revert reasons

* Apply PR feedback from Amir

* Apply PR feedback from Remco

* Re-add networks to ZRXToken artifact

* Remove duplicate Whitelist in compiler.json
2018-07-26 22:09:55 -07:00
fragosti
78a4b9897c Add to README 2018-07-26 16:58:27 -07:00
fragosti
c1fcbe3f04 Create API development environment and json distribution 2018-07-26 16:49:43 -07:00
fragosti
efa67d87aa Rename to sra-api 2018-07-26 14:52:23 -07:00
fragosti
4fe410a277 Add typescript typings for Open API spec 2018-07-26 14:47:02 -07:00
fragosti
3235606644 Reset CHANGELOG 2018-07-26 14:32:22 -07:00
fragosti
260976914d Add basic smoke test 2018-07-26 14:30:24 -07:00
fragosti
3ca4b7e7a7 Initial commit 2018-07-26 13:24:34 -07:00
Fabio Berger
95c627f581 Publish
- 0x.js@1.0.1-rc.2
 - @0xproject/abi-gen@1.0.4
 - @0xproject/assert@1.0.4
 - @0xproject/base-contract@1.0.4
 - @0xproject/connect@1.0.4
 - @0xproject/contract-wrappers@1.0.1-rc.2
 - contracts@2.1.39
 - @0xproject/dev-utils@1.0.3
 - @0xproject/fill-scenarios@1.0.1-rc.2
 - @0xproject/json-schemas@1.0.1-rc.3
 - @0xproject/metacoin@0.0.14
 - @0xproject/migrations@1.0.3
 - @0xproject/order-utils@1.0.1-rc.2
 - @0xproject/order-watcher@1.0.1-rc.2
 - @0xproject/react-docs@1.0.4
 - @0xproject/react-docs-example@0.0.19
 - @0xproject/react-shared@1.0.5
 - @0xproject/sol-compiler@1.0.4
 - @0xproject/sol-cov@1.0.3
 - @0xproject/sol-resolver@1.0.4
 - @0xproject/sra-report@1.0.4
 - @0xproject/subproviders@1.0.4
 - @0xproject/testnet-faucets@1.0.40
 - @0xproject/types@1.0.1-rc.3
 - @0xproject/utils@1.0.4
 - @0xproject/web3-wrapper@1.1.2
 - @0xproject/website@0.0.43
2018-07-26 17:42:30 +02:00
Fabio Berger
512dbb448b Updated CHANGELOGS 2018-07-26 17:42:22 +02:00
Fabio Berger
b793c1cc73 Update yarn.lock 2018-07-26 17:20:48 +02:00
Fabio Berger
aea048ecc7 Point to actual current version 2018-07-26 17:19:26 +02:00
Fabio Berger
d0e6413fcf Add changelog entries for other RCs that did publish 2018-07-26 17:12:17 +02:00
Fabio Berger
3b7ad1688b Fix changelogs and package versions for ones that weren't published 2018-07-26 17:10:59 +02:00
Fabio Berger
e907b99314 Fix circle.yml 2018-07-26 16:57:08 +02:00
Fabio Berger
973bcb0483 Publish
- 0x.js@1.0.1-rc.2
 - @0xproject/abi-gen@1.0.3
 - @0xproject/assert@1.0.3
 - @0xproject/base-contract@1.0.3
 - @0xproject/connect@1.0.3
 - @0xproject/contract-wrappers@1.0.1-rc.2
 - contracts@2.1.38
 - @0xproject/dev-utils@1.0.3
 - ethereum-types@1.0.3
 - @0xproject/fill-scenarios@1.0.1-rc.2
 - @0xproject/json-schemas@1.0.1-rc.2
 - @0xproject/metacoin@0.0.13
 - @0xproject/migrations@1.0.3
 - @0xproject/monorepo-scripts@1.0.4
 - @0xproject/order-utils@1.0.1-rc.2
 - @0xproject/order-watcher@1.0.1-rc.2
 - @0xproject/react-docs@1.0.3
 - @0xproject/react-docs-example@0.0.18
 - @0xproject/react-shared@1.0.4
 - @0xproject/sol-compiler@1.0.3
 - @0xproject/sol-cov@1.0.3
 - @0xproject/sol-resolver@1.0.3
 - @0xproject/sra-report@1.0.3
 - @0xproject/subproviders@1.0.3
 - @0xproject/testnet-faucets@1.0.39
 - @0xproject/tslint-config@1.0.4
 - @0xproject/types@1.0.1-rc.2
 - @0xproject/typescript-typings@1.0.3
 - @0xproject/utils@1.0.3
 - @0xproject/web3-wrapper@1.1.1
 - @0xproject/website@0.0.42
2018-07-26 16:27:08 +02:00
fragosti
490fed6228 Make a non-jank Spinner component and use it 2018-07-24 19:09:02 -07:00
fragosti
9c81692d48 Merge branch 'v2-prototype' of https://github.com/0xProject/0x-monorepo into feature/website/upgrade-allowance-toggles-to-locks-and-checks 2018-07-24 16:02:21 -07:00
fragosti
c505ba6f3e Center allowance toggles in account page 2018-07-24 15:58:33 -07:00
fragosti
ee71f57453 Increase allowance toggle loading spinner size by 1 2018-07-24 15:51:07 -07:00
Olaf Tomalka
f133aebfaf Fixed the relative resolver not checking if the file can be read in the
first place
2018-07-25 00:37:48 +02:00
fragosti
88556d31e2 Add unlocking and locking token copy 2018-07-24 15:32:12 -07:00
fragosti
c0d75c6476 Hide tooltip after allowance toggle click 2018-07-24 15:19:06 -07:00
fragosti
5b6cf447e5 Make tooltip appear to the left of the toggle when onboarding in progress 2018-07-24 15:11:46 -07:00
fragosti
3890f8224d Fix tooltip wrapping issue in onboardin 2018-07-24 14:44:31 -07:00
fragosti
b9f5c93830 Fix wrap button alignment issue 2018-07-24 14:19:19 -07:00
fragosti
0f8e6b395e WIP for allowance toggle redesign working 2018-07-20 10:44:59 -07:00
fragosti
b28cc6d7d3 Show token name dynamically in tooltip 2018-07-20 10:14:17 -07:00
fragosti
3bf12a98a7 Implement tooltips 2018-07-20 09:55:08 -07:00
fragosti
f27084ced4 Add loading state 2018-07-20 09:16:55 -07:00
fragosti
cdcf624e9e Have basic lock and check working in walelt 2018-07-20 08:52:14 -07:00
269 changed files with 7281 additions and 3448 deletions

View File

@@ -56,6 +56,16 @@ jobs:
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
# initialized
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test contracts
test-publish:
docker:
- image: circleci/node:9
- image: verdaccio/verdaccio
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn test:publish:circleci
test-rest:
docker:
- image: circleci/node:9
@@ -80,6 +90,7 @@ jobs:
- run: yarn wsrun test:circleci @0xproject/sra-report
- run: yarn wsrun test:circleci @0xproject/subproviders
- run: yarn wsrun test:circleci @0xproject/web3-wrapper
- run: yarn wsrun test:circleci @0xproject/utils
- save_cache:
key: coverage-0xjs-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -153,7 +164,7 @@ jobs:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn prettier:ci
- run: yarn lerna:run lint
- run: yarn lerna run lint
submit-coverage:
docker:
- image: circleci/node:9
@@ -231,6 +242,9 @@ workflows:
- static-tests:
requires:
- build
- test-publish:
requires:
- build
- submit-coverage:
requires:
- test-rest

View File

@@ -15,6 +15,7 @@ lib
/packages/contract-wrappers/src/artifacts
/packages/order-watcher/src/artifacts
/packages/metacoin/artifacts
/packages/sra-api/public/
/packages/contract-wrappers/test/artifacts
/packages/order-watcher/test/artifacts
/packages/migrations/artifacts/1.0.0

View File

@@ -20,8 +20,8 @@
<!--- The following points should be used to indicate the progress of your PR. Put an `x` in all the boxes that apply right now, and come back over time and check them off as you make progress. If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
* [ ] Prefixed the title of this PR with `[WIP]` if it is a work in progress.
* [ ] Prefixed the title of this PR with bracketed package name(s) corresponding to the changed package(s). For example: `[sol-cov] Fixed bug`.
* [ ] Added tests to cover my changes, or decided that tests would be too impractical.
* [ ] Updated documentation, or decided that no doc change is needed.
* [ ] Added new entries to the relevant CHANGELOG.jsons.
* [ ] Prefix PR title with `[WIP]` if necessary.
* [ ] Prefix PR title with bracketed package name(s) corresponding to the changed package(s). For example: `[sol-cov] Fixed bug`.
* [ ] Add tests to cover changes as needed.
* [ ] Update documentation as needed.
* [ ] Add new entries to the relevant CHANGELOG.jsons.

View File

@@ -82,10 +82,12 @@ We strongly recommend that the community help us make improvements and determine
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
Make sure you are using Yarn v1.6. To install using brew:
```bash
yarn config set workspaces-experimental true
```
brew unlink yarn
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/76215230de5f7f7bee2cfcdd7185cf49d949862d/Formula/yarn.rb
brew switch yarn 1.6.0_1
```
Then install dependencies

View File

@@ -14,6 +14,8 @@
"report_coverage": "lcov-result-merger 'packages/*/coverage/lcov.info' | coveralls",
"test:installation": "node ./packages/monorepo-scripts/lib/test_installation.js",
"test:installation:local": "IS_LOCAL_PUBLISH=true node ./packages/monorepo-scripts/lib/test_installation.js",
"test:publish:circleci:comment": "HACK(albrow) We need an automated way to login to npm and echo+sleep piped to stdin was the only way I could find to do it.",
"test:publish:circleci": "{ echo \"test\"; sleep 1; echo \"test\"; sleep 1; echo \"test@example.com\"; } | npm login --registry=http://localhost:4873 && IS_LOCAL_PUBLISH=true run-s script:publish test:installation:local",
"run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild:no_website script:publish",
"run:publish:local": "IS_LOCAL_PUBLISH=true yarn run:publish",
"script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js",
@@ -38,11 +40,11 @@
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
},
"devDependencies": {
"@0x-lerna-fork/lerna": "3.0.0-beta.23",
"async-child-process": "^1.1.1",
"coveralls": "^3.0.0",
"ganache-cli": "6.1.3",
"lcov-result-merger": "^3.0.0",
"@0x-lerna-fork/lerna": "3.0.0-beta.23",
"npm-run-all": "^4.1.2",
"prettier": "^1.11.1",
"source-map-support": "^0.5.6",

View File

@@ -1,4 +1,17 @@
[
{
"version": "1.0.1-rc.3",
"changes": [
{
"note": "Dependencies updated"
},
{
"pr": 914,
"note": "Update ecSignOrderHashAsync to return the signature as a string for immediate use in contracts"
}
],
"timestamp": 1534210131
},
{
"version": "1.0.1-rc.2",
"changes": [
@@ -6,7 +19,7 @@
"note": "Fixed bug caused by importing non-existent dep"
}
],
"timestamp": 1532614997
"timestamp": 1532619515
},
{
"version": "1.0.1-rc.1",

View File

@@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.1-rc.3 - _August 13, 2018_
* Dependencies updated
* Update ecSignOrderHashAsync to return the signature as a string for immediate use in contracts (#914)
## v1.0.1-rc.2 - _July 26, 2018_
* Fixed bug caused by importing non-existent dep
@@ -17,11 +22,11 @@ CHANGELOG
* Dependencies updated
## v1.0.0-rc.2 - _July 20, 2018_
## v1.0.0-rc.2 - _July 19, 2018_
* Remove `zeroEx.assetData` and instead re-export it's static functions directly off `ZeroEx`
## v1.0.0-rc.1 - _July 20, 2018_
## v1.0.0-rc.1 - _July 19, 2018_
* Remove tokenRegistry wrapper (#863)
* Rename `zeroEx.token` to `zeroEx.erc20Token`, and add `zeroEx.erc721Token` (#863)
@@ -61,7 +66,7 @@ CHANGELOG
* Renamed createOrderStateWatcher to createOrderWatcherAsync since it is now async (#579)
* Renamed ZeroExError to ContractWrappersErrors since they now lives in the @0xproject/contract-wrappers subpackage (#579)
## v0.37.2 - _May 5, 2018_
## v0.37.2 - _May 4, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "0x.js",
"version": "1.0.1-rc.1",
"version": "1.0.1-rc.2",
"engines": {
"node": ">=6.12"
},
@@ -68,11 +68,11 @@
},
"license": "Apache-2.0",
"devDependencies": {
"@0xproject/abi-gen": "^1.0.2",
"@0xproject/dev-utils": "^1.0.2",
"@0xproject/migrations": "^1.0.2",
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/abi-gen": "^1.0.4",
"@0xproject/dev-utils": "^1.0.3",
"@0xproject/migrations": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/node": "^8.0.53",
@@ -85,7 +85,7 @@
"dirty-chai": "^2.0.1",
"json-loader": "^0.5.4",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"opn-cli": "^3.1.0",
@@ -94,23 +94,23 @@
"source-map-support": "^0.5.0",
"tslint": "5.11.0",
"typedoc": "0xProject/typedoc",
"typescript": "2.7.1",
"typescript": "2.9.2",
"webpack": "^3.1.0"
},
"dependencies": {
"@0xproject/assert": "^1.0.2",
"@0xproject/base-contract": "^1.0.2",
"@0xproject/contract-wrappers": "^1.0.1-rc.1",
"@0xproject/order-utils": "^1.0.1-rc.1",
"@0xproject/sol-compiler": "^1.0.2",
"@0xproject/subproviders": "^1.0.2",
"@0xproject/types": "^1.0.1-rc.1",
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"@0xproject/web3-wrapper": "^1.1.0",
"ethereum-types": "^1.0.2",
"@0xproject/assert": "^1.0.4",
"@0xproject/base-contract": "^1.0.4",
"@0xproject/contract-wrappers": "^1.0.1-rc.2",
"@0xproject/order-utils": "^1.0.1-rc.2",
"@0xproject/sol-compiler": "^1.0.4",
"@0xproject/subproviders": "^1.0.4",
"@0xproject/types": "^1.0.1-rc.3",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"@0xproject/web3-wrapper": "^1.1.2",
"ethereum-types": "^1.0.3",
"ethers": "3.0.22",
"lodash": "^4.17.4"
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"

View File

@@ -14,13 +14,12 @@ import {
ecSignOrderHashAsync,
generatePseudoRandomSalt,
isValidSignatureAsync,
MessagePrefixOpts,
orderHashUtils,
} from '@0xproject/order-utils';
// HACK: Since we export assetDataUtils from ZeroEx and it has AssetProxyId, ERC20AssetData and ERC721AssetData
// in it's public interface, we need to import these types here.
// tslint:disable-next-line:no-unused-variable
import { AssetProxyId, ECSignature, ERC20AssetData, ERC721AssetData, Order, SignedOrder } from '@0xproject/types';
import { AssetProxyId, ERC20AssetData, ERC721AssetData, Order, SignedOrder, SignerType } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
@@ -238,19 +237,21 @@ export class ZeroEx {
* @param orderHash Hex encoded orderHash to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
* must be available via the Provider supplied to 0x.js.
* @param MessagePrefixOpts Options regarding the desired prefix and whether to add it before calling `eth_sign`
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
* @param signerType the signer type that will perform the `eth_sign` operation. E.g Default, Metamask, Ledger or Trezor.
* Some implementations exhibit different behaviour. Default will assume a spec compliant eth_sign implementation.
* This parameter is defaulted to `SignerType.Default`.
* @return A hex encoded string of the Elliptic curve signature parameters generated by signing the orderHash and signature type.
*/
public async ecSignOrderHashAsync(
orderHash: string,
signerAddress: string,
messagePrefixOpts: MessagePrefixOpts,
): Promise<ECSignature> {
signerType: SignerType = SignerType.Default,
): Promise<string> {
const signature = await ecSignOrderHashAsync(
this._contractWrappers.getProvider(),
orderHash,
signerAddress,
messagePrefixOpts,
signerType,
);
return signature;
}

View File

@@ -1,12 +1,12 @@
export { ZeroEx } from './0x';
export { MessagePrefixType, MessagePrefixOpts } from '@0xproject/order-utils';
export { Web3ProviderEngine, RPCSubprovider } from '@0xproject/subproviders';
export {
ExchangeContractErrs,
Order,
SignedOrder,
SignerType,
ECSignature,
OrderStateValid,
OrderStateInvalid,

View File

@@ -48,10 +48,11 @@ describe('ZeroEx library', () => {
const ethSignSignature =
'0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403';
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
const bytes32Zeros = '0x0000000000000000000000000000000000000000000000000000000000000000';
it("should return false if the data doesn't pertain to the signature & address", async () => {
return expect((zeroEx.exchange as any).isValidSignatureAsync('0x0', address, ethSignSignature)).to.become(
false,
);
return expect(
(zeroEx.exchange as any).isValidSignatureAsync(bytes32Zeros, address, ethSignSignature),
).to.become(false);
});
it("should return false if the address doesn't pertain to the signature & data", async () => {
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.5 - _August 13, 2018_
* Dependencies updated
## v1.0.4 - _July 26, 2018_
* Dependencies updated
## v1.0.3 - _July 26, 2018_
* Dependencies updated
@@ -17,7 +25,7 @@ CHANGELOG
* Fix the abi-gen entry point in package.json (#901)
## v1.0.0 - _July 20, 2018_
## v1.0.0 - _July 19, 2018_
* Convert e_r_c to erc in generated file names (#822)
* Remove the output directory before writing to it (#822)
@@ -35,7 +43,7 @@ CHANGELOG
* Dependencies updated
## v0.3.1 - _June 1, 2018_
## v0.3.1 - _May 31, 2018_
* Incorrect publish that was unpublished
@@ -43,7 +51,7 @@ CHANGELOG
* Properly export the executable binary (#588)
## v0.2.13 - _May 5, 2018_
## v0.2.13 - _May 4, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/abi-gen",
"version": "1.0.2",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
@@ -32,13 +32,13 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
"dependencies": {
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"chalk": "^2.3.0",
"ethereum-types": "^1.0.2",
"ethereum-types": "^1.0.3",
"glob": "^7.1.2",
"handlebars": "^4.0.11",
"lodash": "^4.17.4",
"lodash": "^4.17.5",
"mkdirp": "^0.5.1",
"sleep": "^5.1.1",
"tmp": "^0.0.33",
@@ -46,8 +46,8 @@
"yargs": "^10.0.3"
},
"devDependencies": {
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/glob": "5.0.35",
"@types/handlebars": "^4.0.36",
"@types/mkdirp": "^0.5.1",
@@ -63,7 +63,7 @@
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"publishConfig": {
"access": "public"

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.5 - _August 13, 2018_
* Dependencies updated
## v1.0.4 - _July 26, 2018_
* Dependencies updated
## v1.0.3 - _July 26, 2018_
* Dependencies updated
@@ -17,7 +25,7 @@ CHANGELOG
* Dependencies updated
## v1.0.0 - _July 20, 2018_
## v1.0.0 - _July 19, 2018_
* Fix bug in string enum assertion. We erroneously were checking against the enum keys, not values (#821)
@@ -33,7 +41,7 @@ CHANGELOG
* Dependencies updated
## v0.2.11 - _June 1, 2018_
## v0.2.11 - _May 31, 2018_
* Incorrect publish that was unpublished
@@ -41,7 +49,7 @@ CHANGELOG
* Dependencies updated
## v0.2.9 - _May 5, 2018_
## v0.2.9 - _May 4, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/assert",
"version": "1.0.2",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
@@ -30,8 +30,8 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md",
"devDependencies": {
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/valid-url": "^1.0.2",
@@ -39,18 +39,18 @@
"copyfiles": "^1.2.0",
"dirty-chai": "^2.0.1",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"dependencies": {
"@0xproject/json-schemas": "^1.0.1-rc.1",
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"lodash": "^4.17.4",
"@0xproject/json-schemas": "^1.0.1-rc.3",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"lodash": "^4.17.5",
"valid-url": "^1.0.9"
},
"publishConfig": {

View File

@@ -1,4 +1,23 @@
[
{
"version": "2.0.0-rc.1",
"changes": [
{
"pr": 915,
"note": "Added strict encoding/decoding checks for sendTransaction and call"
}
],
"timestamp": 1534210131
},
{
"timestamp": 1532619515,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1532614997,
"version": "1.0.3",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.0-rc.1 - _August 13, 2018_
* Added strict encoding/decoding checks for sendTransaction and call (#915)
## v1.0.4 - _July 26, 2018_
* Dependencies updated
## v1.0.3 - _July 26, 2018_
* Dependencies updated
@@ -17,7 +25,7 @@ CHANGELOG
* Dependencies updated
## v1.0.0 - _July 20, 2018_
## v1.0.0 - _July 19, 2018_
* Dependencies updated
@@ -33,7 +41,7 @@ CHANGELOG
* Update EthersJs to fix the `value.toLowerCase()` is not a function bug caused by `ethers.js` breaking patch version https://github.com/ethers-io/ethers.js/issues/201
## v0.3.3 - _June 1, 2018_
## v0.3.3 - _May 31, 2018_
* Incorrect publish that was unpublished
@@ -41,7 +49,7 @@ CHANGELOG
* Dependencies updated
## v0.3.1 - _May 5, 2018_
## v0.3.1 - _May 4, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/base-contract",
"version": "1.0.2",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
@@ -30,25 +30,25 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md",
"devDependencies": {
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/lodash": "4.14.104",
"chai": "^4.0.1",
"copyfiles": "^1.2.0",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"dependencies": {
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"@0xproject/web3-wrapper": "^1.1.0",
"ethereum-types": "^1.0.2",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"@0xproject/web3-wrapper": "^1.1.2",
"ethereum-types": "^1.0.3",
"ethers": "3.0.22",
"lodash": "^4.17.4"
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"

View File

@@ -82,6 +82,27 @@ export class BaseContract {
}
return txDataWithDefaults;
}
// Throws if the given arguments cannot be safely/correctly encoded based on
// the given inputAbi. An argument may not be considered safely encodeable
// if it overflows the corresponding Solidity type, there is a bug in the
// encoder, or the encoder performs unsafe type coercion.
public static strictArgumentEncodingCheck(inputAbi: DataItem[], args: any[]): void {
const coder = ethers.utils.AbiCoder.defaultCoder;
const params = abiUtils.parseEthersParams(inputAbi);
const rawEncoded = coder.encode(params.names, params.types, args);
const rawDecoded = coder.decode(params.names, params.types, rawEncoded);
for (let i = 0; i < rawDecoded.length; i++) {
const original = args[i];
const decoded = rawDecoded[i];
if (!abiUtils.isAbiDataEqual(params.names[i], params.types[i], original, decoded)) {
throw new Error(
`Cannot safely encode argument: ${params.names[i]} (${original}) of type ${
params.types[i]
}. (Possible type overflow or other encoding error)`,
);
}
}
}
protected _lookupEthersInterface(functionSignature: string): ethers.Interface {
const ethersInterface = this._ethersInterfacesByFunctionSignature[functionSignature];
if (_.isUndefined(ethersInterface)) {

View File

@@ -0,0 +1,114 @@
import * as chai from 'chai';
import 'mocha';
import { BaseContract } from '../src';
const { expect } = chai;
describe('BaseContract', () => {
describe('strictArgumentEncodingCheck', () => {
it('works for simple types', () => {
BaseContract.strictArgumentEncodingCheck(
[{ name: 'to', type: 'address' }],
['0xe834ec434daba538cd1b9fe1582052b880bd7e63'],
);
});
it('works for array types', () => {
const inputAbi = [
{
name: 'takerAssetFillAmounts',
type: 'uint256[]',
},
];
const args = [
['9000000000000000000', '79000000000000000000', '979000000000000000000', '7979000000000000000000'],
];
BaseContract.strictArgumentEncodingCheck(inputAbi, args);
});
it('works for tuple/struct types', () => {
const inputAbi = [
{
components: [
{
name: 'makerAddress',
type: 'address',
},
{
name: 'takerAddress',
type: 'address',
},
{
name: 'feeRecipientAddress',
type: 'address',
},
{
name: 'senderAddress',
type: 'address',
},
{
name: 'makerAssetAmount',
type: 'uint256',
},
{
name: 'takerAssetAmount',
type: 'uint256',
},
{
name: 'makerFee',
type: 'uint256',
},
{
name: 'takerFee',
type: 'uint256',
},
{
name: 'expirationTimeSeconds',
type: 'uint256',
},
{
name: 'salt',
type: 'uint256',
},
{
name: 'makerAssetData',
type: 'bytes',
},
{
name: 'takerAssetData',
type: 'bytes',
},
],
name: 'order',
type: 'tuple',
},
];
const args = [
{
makerAddress: '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb',
takerAddress: '0x0000000000000000000000000000000000000000',
feeRecipientAddress: '0xe834ec434daba538cd1b9fe1582052b880bd7e63',
senderAddress: '0x0000000000000000000000000000000000000000',
makerAssetAmount: '0',
takerAssetAmount: '200000000000000000000',
makerFee: '1000000000000000000',
takerFee: '1000000000000000000',
expirationTimeSeconds: '1532563026',
salt: '59342956082154660870994022243365949771115859664887449740907298019908621891376',
makerAssetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
takerAssetData: '0xf47261b00000000000000000000000001d7022f5b17d2f8b695918fb48fa1089c9f85401',
},
];
BaseContract.strictArgumentEncodingCheck(inputAbi, args);
});
it('throws for integer overflows', () => {
expect(() =>
BaseContract.strictArgumentEncodingCheck([{ name: 'amount', type: 'uint8' }], ['256']),
).to.throw();
});
it('throws for fixed byte array overflows', () => {
expect(() =>
BaseContract.strictArgumentEncodingCheck([{ name: 'hash', type: 'bytes8' }], ['0x001122334455667788']),
).to.throw();
});
});
});

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.5 - _August 13, 2018_
* Dependencies updated
## v1.0.4 - _July 26, 2018_
* Dependencies updated
## v1.0.3 - _July 26, 2018_
* Dependencies updated
@@ -17,7 +25,7 @@ CHANGELOG
* Dependencies updated
## v1.0.0 - _July 20, 2018_
## v1.0.0 - _July 19, 2018_
* Remove `WebSocketOrderbookChannel` from the public interface and replace with `orderbookChannelFactory`
@@ -41,7 +49,7 @@ CHANGELOG
* Dependencies updated
## v0.6.12 - _May 5, 2018_
## v0.6.12 - _May 4, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/connect",
"version": "1.0.2",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
@@ -54,16 +54,16 @@
"@0xproject/assert": "^0.2.14",
"@0xproject/json-schemas": "^0.8.3",
"@0xproject/types": "^0.8.2",
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"lodash": "^4.17.4",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"lodash": "^4.17.5",
"query-string": "^5.0.1",
"sinon": "^4.0.0",
"websocket": "^1.0.25"
},
"devDependencies": {
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/fetch-mock": "^5.12.2",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
@@ -77,13 +77,13 @@
"dirty-chai": "^2.0.1",
"fetch-mock": "^5.13.1",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typedoc": "~0.8.0",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"publishConfig": {
"access": "public"

View File

@@ -1,4 +1,22 @@
[
{
"version": "1.0.1-rc.3",
"changes": [
{
"pr": 915,
"note": "Added strict encoding/decoding checks for sendTransaction and call"
},
{
"note": "Add ForwarderWrapper",
"pr": 934
},
{
"note": "Optimize orders in ForwarderWrapper",
"pr": 936
}
],
"timestamp": 1534210131
},
{
"version": "1.0.1-rc.2",
"changes": [
@@ -6,7 +24,7 @@
"note": "Fixed bug caused by importing non-existent dep"
}
],
"timestamp": 1532614997
"timestamp": 1532619515
},
{
"version": "1.0.1-rc.1",

View File

@@ -5,6 +5,12 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.1-rc.3 - _August 13, 2018_
* Added strict encoding/decoding checks for sendTransaction and call (#915)
* Add ForwarderWrapper (#934)
* Optimize orders in ForwarderWrapper (#936)
## v1.0.1-rc.2 - _July 26, 2018_
* Fixed bug caused by importing non-existent dep
@@ -17,7 +23,7 @@ CHANGELOG
* Dependencies updated
## v1.0.0-rc.1 - _July 20, 2018_
## v1.0.0-rc.1 - _July 19, 2018_
* Update blockstream to v5.0 and propogate up caught errors to active subscriptions (#815)
* Update to v2 of 0x rpotocol (#822)

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/contract-wrappers",
"version": "1.0.1-rc.1",
"version": "1.0.1-rc.2",
"description": "Smart TS wrappers for 0x smart contracts",
"keywords": [
"0xproject",
@@ -14,7 +14,7 @@
"watch_without_deps": "yarn pre_build && tsc -w",
"build": "yarn pre_build && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"pre_build": "run-s update_artifacts_v2_beta update_artifacts_v2 generate_contract_wrappers copy_artifacts",
"generate_contract_wrappers": "abi-gen --abis 'src/artifacts/@(Exchange|DummyERC20Token|DummyERC721Token|ZRXToken|ERC20Token|ERC721Token|WETH9|ERC20Proxy|ERC721Proxy).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers",
"generate_contract_wrappers": "abi-gen --abis 'src/artifacts/@(Exchange|DummyERC20Token|DummyERC721Token|ZRXToken|ERC20Token|ERC721Token|WETH9|ERC20Proxy|ERC721Proxy|Forwarder).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers",
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
@@ -29,7 +29,7 @@
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
},
"config": {
"contracts_v2_beta": "Exchange ERC20Proxy ERC20Token ERC721Proxy ERC721Token WETH9 ZRXToken",
"contracts_v2_beta": "Exchange ERC20Proxy ERC20Token ERC721Proxy ERC721Token WETH9 ZRXToken Forwarder",
"contracts_v2": "DummyERC20Token DummyERC721Token"
},
"repository": {
@@ -41,13 +41,13 @@
"node": ">=6.0.0"
},
"devDependencies": {
"@0xproject/abi-gen": "^1.0.2",
"@0xproject/dev-utils": "^1.0.2",
"@0xproject/migrations": "^1.0.2",
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/sol-compiler": "^1.0.2",
"@0xproject/subproviders": "^1.0.2",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/abi-gen": "^1.0.4",
"@0xproject/dev-utils": "^1.0.3",
"@0xproject/migrations": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/sol-compiler": "^1.0.4",
"@0xproject/subproviders": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/node": "^8.0.53",
@@ -60,7 +60,7 @@
"copyfiles": "^1.2.0",
"dirty-chai": "^2.0.1",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"opn-cli": "^3.1.0",
@@ -68,25 +68,25 @@
"sinon": "^4.0.0",
"source-map-support": "^0.5.0",
"tslint": "5.11.0",
"typescript": "2.7.1",
"typescript": "2.9.2",
"web3-provider-engine": "14.0.6"
},
"dependencies": {
"@0xproject/assert": "^1.0.2",
"@0xproject/base-contract": "^1.0.2",
"@0xproject/fill-scenarios": "^1.0.1-rc.1",
"@0xproject/json-schemas": "^1.0.1-rc.1",
"@0xproject/order-utils": "^1.0.1-rc.1",
"@0xproject/types": "^1.0.1-rc.1",
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"@0xproject/web3-wrapper": "^1.1.0",
"ethereum-types": "^1.0.2",
"@0xproject/assert": "^1.0.4",
"@0xproject/base-contract": "^1.0.4",
"@0xproject/fill-scenarios": "^1.0.1-rc.2",
"@0xproject/json-schemas": "^1.0.1-rc.3",
"@0xproject/order-utils": "^1.0.1-rc.2",
"@0xproject/types": "^1.0.1-rc.3",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"@0xproject/web3-wrapper": "^1.1.2",
"ethereum-types": "^1.0.3",
"ethereumjs-blockstream": "5.0.0",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
"js-sha3": "^0.7.0",
"lodash": "^4.17.4",
"lodash": "^4.17.5",
"uuid": "^3.1.0"
},
"publishConfig": {

View File

@@ -7,6 +7,7 @@ import * as ERC20Token from './artifacts/ERC20Token.json';
import * as ERC721Proxy from './artifacts/ERC721Proxy.json';
import * as ERC721Token from './artifacts/ERC721Token.json';
import * as Exchange from './artifacts/Exchange.json';
import * as Forwarder from './artifacts/Forwarder.json';
import * as EtherToken from './artifacts/WETH9.json';
import * as ZRXToken from './artifacts/ZRXToken.json';
@@ -20,4 +21,5 @@ export const artifacts = {
EtherToken: (EtherToken as any) as ContractArtifact,
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
Forwarder: (Forwarder as any) as ContractArtifact,
};

View File

@@ -11,6 +11,7 @@ import { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
import { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper';
import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
import { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
import { ContractWrappersConfigSchema } from './schemas/contract_wrappers_config_schema';
import { contractWrappersPrivateNetworkConfigSchema } from './schemas/contract_wrappers_private_network_config_schema';
import { contractWrappersPublicNetworkConfigSchema } from './schemas/contract_wrappers_public_network_config_schema';
@@ -47,6 +48,11 @@ export class ContractWrappers {
* erc721Proxy smart contract.
*/
public erc721Proxy: ERC721ProxyWrapper;
/**
* An instance of the ForwarderWrapper class containing methods for interacting with any Forwarder smart contract.
*/
public forwarder: ForwarderWrapper;
private _web3Wrapper: Web3Wrapper;
/**
* Instantiates a new ContractWrappers instance.
@@ -104,6 +110,12 @@ export class ContractWrappers {
config.zrxContractAddress,
blockPollingIntervalMs,
);
this.forwarder = new ForwarderWrapper(
this._web3Wrapper,
config.networkId,
config.forwarderContractAddress,
config.zrxContractAddress,
);
}
/**
* Sets a new web3 provider for 0x.js. Updating the provider will stop all

View File

@@ -869,15 +869,35 @@ export class ExchangeWrapper extends ContractWrapper {
*/
@decorators.asyncZeroExErrorHandler
public async getOrderInfoAsync(order: Order | SignedOrder, methodOpts: MethodOpts = {}): Promise<OrderInfo> {
assert.doesConformToSchema('order', order, schemas.orderSchema);
if (!_.isUndefined(methodOpts)) {
assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema);
}
const exchangeInstance = await this._getExchangeContractAsync();
const txData = {};
const orderInfo = await exchangeInstance.getOrderInfo.callAsync(order, txData, methodOpts.defaultBlock);
return orderInfo;
}
/**
* Get order info for multiple orders
* @param orders Orders
* @param methodOpts Optional arguments this method accepts.
* @returns Array of Order infos
*/
@decorators.asyncZeroExErrorHandler
public async getOrdersInfoAsync(
orders: Array<Order | SignedOrder>,
methodOpts: MethodOpts = {},
): Promise<OrderInfo[]> {
assert.doesConformToSchema('orders', orders, schemas.ordersSchema);
if (!_.isUndefined(methodOpts)) {
assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema);
}
const exchangeInstance = await this._getExchangeContractAsync();
const txData = {};
const ordersInfo = await exchangeInstance.getOrdersInfo.callAsync(orders, txData, methodOpts.defaultBlock);
return ordersInfo;
}
/**
* Cancel a given order.
* @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel.

View File

@@ -0,0 +1,220 @@
import { schemas } from '@0xproject/json-schemas';
import { AssetProxyId, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { ContractAbi } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from '../artifacts';
import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
import { txOptsSchema } from '../schemas/tx_opts_schema';
import { TransactionOpts } from '../types';
import { assert } from '../utils/assert';
import { calldataOptimizationUtils } from '../utils/calldata_optimization_utils';
import { constants } from '../utils/constants';
import { ContractWrapper } from './contract_wrapper';
import { ForwarderContract } from './generated/forwarder';
/**
* This class includes the functionality related to interacting with the Forwarder contract.
*/
export class ForwarderWrapper extends ContractWrapper {
public abi: ContractAbi = artifacts.Forwarder.compilerOutput.abi;
private _forwarderContractIfExists?: ForwarderContract;
private _contractAddressIfExists?: string;
private _zrxContractAddressIfExists?: string;
constructor(
web3Wrapper: Web3Wrapper,
networkId: number,
contractAddressIfExists?: string,
zrxContractAddressIfExists?: string,
) {
super(web3Wrapper, networkId);
this._contractAddressIfExists = contractAddressIfExists;
this._zrxContractAddressIfExists = zrxContractAddressIfExists;
}
/**
* Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
* Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
* 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
* Any ETH not spent will be refunded to sender.
* @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
* All orders must specify WETH as the takerAsset
* @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
* Provider provided at instantiation.
* @param ethAmount The amount of eth to send with the transaction (in wei).
* @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
* Used to purchase ZRX for primary order fees.
* @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
* Defaults to 0.
* @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async marketSellOrdersWithEthAsync(
signedOrders: SignedOrder[],
takerAddress: string,
ethAmount: BigNumber,
signedFeeOrders: SignedOrder[] = [],
feePercentage: BigNumber = constants.ZERO_AMOUNT,
feeRecipientAddress: string = constants.NULL_ADDRESS,
txOpts: TransactionOpts = {},
): Promise<string> {
// type assertions
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
assert.isBigNumber('ethAmount', ethAmount);
assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
assert.isBigNumber('feePercentage', feePercentage);
assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
// other assertions
assert.ordersCanBeUsedForForwarderContract(signedOrders, this.getEtherTokenAddress());
assert.feeOrdersCanBeUsedForForwarderContract(
signedFeeOrders,
this.getZRXTokenAddress(),
this.getEtherTokenAddress(),
);
// lowercase input addresses
const normalizedTakerAddress = takerAddress.toLowerCase();
const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
// optimize orders
const optimizedMarketOrders = calldataOptimizationUtils.optimizeForwarderOrders(signedOrders);
const optimizedFeeOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(signedFeeOrders);
// send transaction
const forwarderContractInstance = await this._getForwarderContractAsync();
const txHash = await forwarderContractInstance.marketSellOrdersWithEth.sendTransactionAsync(
optimizedMarketOrders,
_.map(optimizedMarketOrders, order => order.signature),
optimizedFeeOrders,
_.map(optimizedFeeOrders, order => order.signature),
feePercentage,
feeRecipientAddress,
{
value: ethAmount,
from: normalizedTakerAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
},
);
return txHash;
}
/**
* Attempt to purchase makerAssetFillAmount of makerAsset by selling ethAmount provided with transaction.
* Any ZRX required to pay fees for primary orders will automatically be purchased by the contract.
* Any ETH not spent will be refunded to sender.
* @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
* All orders must specify WETH as the takerAsset
* @param makerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill.
* @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
* Provider provided at instantiation.
* @param ethAmount The amount of eth to send with the transaction (in wei).
* @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
* Used to purchase ZRX for primary order fees.
* @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
* Defaults to 0.
* @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async marketBuyOrdersWithEthAsync(
signedOrders: SignedOrder[],
makerAssetFillAmount: BigNumber,
takerAddress: string,
ethAmount: BigNumber,
signedFeeOrders: SignedOrder[] = [],
feePercentage: BigNumber = constants.ZERO_AMOUNT,
feeRecipientAddress: string = constants.NULL_ADDRESS,
txOpts: TransactionOpts = {},
): Promise<string> {
// type assertions
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
assert.isBigNumber('ethAmount', ethAmount);
assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
assert.isBigNumber('feePercentage', feePercentage);
assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
// other assertions
assert.ordersCanBeUsedForForwarderContract(signedOrders, this.getEtherTokenAddress());
assert.feeOrdersCanBeUsedForForwarderContract(
signedFeeOrders,
this.getZRXTokenAddress(),
this.getEtherTokenAddress(),
);
// lowercase input addresses
const normalizedTakerAddress = takerAddress.toLowerCase();
const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
// optimize orders
const optimizedMarketOrders = calldataOptimizationUtils.optimizeForwarderOrders(signedOrders);
const optimizedFeeOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(signedFeeOrders);
// send transaction
const forwarderContractInstance = await this._getForwarderContractAsync();
const txHash = await forwarderContractInstance.marketBuyOrdersWithEth.sendTransactionAsync(
optimizedMarketOrders,
makerAssetFillAmount,
_.map(optimizedMarketOrders, order => order.signature),
optimizedFeeOrders,
_.map(optimizedFeeOrders, order => order.signature),
feePercentage,
feeRecipientAddress,
{
value: ethAmount,
from: normalizedTakerAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
},
);
return txHash;
}
/**
* Retrieves the Ethereum address of the Forwarder contract deployed on the network
* that the user-passed web3 provider is connected to.
* @returns The Ethereum address of the Forwarder contract being used.
*/
public getContractAddress(): string {
const contractAddress = this._getContractAddress(artifacts.Forwarder, this._contractAddressIfExists);
return contractAddress;
}
/**
* Returns the ZRX token address used by the forwarder contract.
* @return Address of ZRX token
*/
public getZRXTokenAddress(): string {
const contractAddress = this._getContractAddress(artifacts.ZRXToken, this._zrxContractAddressIfExists);
return contractAddress;
}
/**
* Returns the Ether token address used by the forwarder contract.
* @return Address of Ether token
*/
public getEtherTokenAddress(): string {
const contractAddress = this._getContractAddress(artifacts.EtherToken);
return contractAddress;
}
// HACK: We don't want this method to be visible to the other units within that package but not to the end user.
// TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
// tslint:disable-next-line:no-unused-variable
private _invalidateContractInstance(): void {
delete this._forwarderContractIfExists;
}
private async _getForwarderContractAsync(): Promise<ForwarderContract> {
if (!_.isUndefined(this._forwarderContractIfExists)) {
return this._forwarderContractIfExists;
}
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
artifacts.Forwarder,
this._contractAddressIfExists,
);
const contractInstance = new ForwarderContract(
abi,
address,
this._web3Wrapper.getProvider(),
this._web3Wrapper.getContractDefaults(),
);
this._forwarderContractIfExists = contractInstance;
return this._forwarderContractIfExists;
}
}

View File

@@ -5,6 +5,7 @@ export { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
export { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
export { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
export { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
export { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
export {
ContractWrappersError,

View File

@@ -5,11 +5,11 @@ export const contractWrappersPrivateNetworkConfigSchema = {
type: 'number',
minimum: 1,
},
gasPrice: { $ref: '/Number' },
zrxContractAddress: { $ref: '/Address' },
exchangeContractAddress: { $ref: '/Address' },
erc20ProxyContractAddress: { $ref: '/Address' },
erc721ProxyContractAddress: { $ref: '/Address' },
gasPrice: { $ref: '/numberSchema' },
zrxContractAddress: { $ref: '/addressSchema' },
exchangeContractAddress: { $ref: '/addressSchema' },
erc20ProxyContractAddress: { $ref: '/addressSchema' },
erc721ProxyContractAddress: { $ref: '/addressSchema' },
blockPollingIntervalMs: { type: 'number' },
orderWatcherConfig: {
type: 'object',

View File

@@ -19,11 +19,11 @@ export const contractWrappersPublicNetworkConfigSchema = {
networkNameToId.ganache,
],
},
gasPrice: { $ref: '/Number' },
zrxContractAddress: { $ref: '/Address' },
exchangeContractAddress: { $ref: '/Address' },
erc20ProxyContractAddress: { $ref: '/Address' },
erc721ProxyContractAddress: { $ref: '/Address' },
gasPrice: { $ref: '/numberSchema' },
zrxContractAddress: { $ref: '/addressSchema' },
exchangeContractAddress: { $ref: '/addressSchema' },
erc20ProxyContractAddress: { $ref: '/addressSchema' },
erc721ProxyContractAddress: { $ref: '/addressSchema' },
blockPollingIntervalMs: { type: 'number' },
orderWatcherConfig: {
type: 'object',

View File

@@ -1,7 +1,7 @@
export const methodOptsSchema = {
id: '/MethodOpts',
properties: {
defaultBlock: { $ref: '/BlockParam' },
defaultBlock: { $ref: '/blockParamSchema' },
},
type: 'object',
};

View File

@@ -1,7 +1,7 @@
export const txOptsSchema = {
id: '/TxOpts',
properties: {
gasPrice: { $ref: '/Number' },
gasPrice: { $ref: '/numberSchema' },
gasLimit: { type: 'number' },
},
type: 'object',

View File

@@ -109,6 +109,7 @@ export type SyncMethod = (...args: any[]) => any;
* zrxContractAddress: The address of the ZRX contract to use
* erc20ProxyContractAddress: The address of the erc20 token transfer proxy contract to use
* erc721ProxyContractAddress: The address of the erc721 token transfer proxy contract to use
* forwarderContractAddress: The address of the forwarder contract to use
* orderWatcherConfig: All the configs related to the orderWatcher
* blockPollingIntervalMs: The interval to use for block polling in event watching methods (defaults to 1000)
*/
@@ -119,6 +120,7 @@ export interface ContractWrappersConfig {
zrxContractAddress?: string;
erc20ProxyContractAddress?: string;
erc721ProxyContractAddress?: string;
forwarderContractAddress?: string;
blockPollingIntervalMs?: number;
}
@@ -172,13 +174,13 @@ export enum TransferType {
export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void;
export interface OrderInfo {
orderStatus: number;
orderStatus: OrderStatus;
orderHash: string;
orderTakerAssetFilledAmount: BigNumber;
}
export enum OrderStatus {
INVALID,
INVALID = 0,
INVALID_MAKER_ASSET_AMOUNT,
INVALID_TAKER_ASSET_AMOUNT,
FILLABLE,

View File

@@ -1,11 +1,14 @@
import { assert as sharedAssert } from '@0xproject/assert';
// HACK: We need those two unused imports because they're actually used by sharedAssert which gets injected here
import { Schema } from '@0xproject/json-schemas'; // tslint:disable-line:no-unused-variable
import { isValidSignatureAsync } from '@0xproject/order-utils';
import { ECSignature } from '@0xproject/types'; // tslint:disable-line:no-unused-variable
import { assetDataUtils, isValidSignatureAsync } from '@0xproject/order-utils';
import { ECSignature, Order } from '@0xproject/types'; // tslint:disable-line:no-unused-variable
import { BigNumber } from '@0xproject/utils'; // tslint:disable-line:no-unused-variable
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
import { constants } from './constants';
export const assert = {
...sharedAssert,
@@ -16,12 +19,12 @@ export const assert = {
signerAddress: string,
): Promise<void> {
const isValid = await isValidSignatureAsync(provider, orderHash, signature, signerAddress);
this.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
sharedAssert.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
},
isValidSubscriptionToken(variableName: string, subscriptionToken: string): void {
const uuidRegex = new RegExp('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$');
const isValid = uuidRegex.test(subscriptionToken);
this.assert(isValid, `Expected ${variableName} to be a valid subscription token`);
sharedAssert.assert(isValid, `Expected ${variableName} to be a valid subscription token`);
},
async isSenderAddressAsync(
variableName: string,
@@ -35,4 +38,53 @@ export const assert = {
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
);
},
ordersCanBeUsedForForwarderContract(orders: Order[], etherTokenAddress: string): void {
sharedAssert.assert(!_.isEmpty(orders), 'Expected at least 1 signed order. Found no orders');
assert.ordersHaveAtMostOneUniqueValueForProperty(orders, 'makerAssetData');
assert.allTakerAssetDatasAreErc20Token(orders, etherTokenAddress);
assert.allTakerAddressesAreNull(orders);
},
feeOrdersCanBeUsedForForwarderContract(orders: Order[], zrxTokenAddress: string, etherTokenAddress: string): void {
if (!_.isEmpty(orders)) {
assert.allMakerAssetDatasAreErc20Token(orders, zrxTokenAddress);
assert.allTakerAssetDatasAreErc20Token(orders, etherTokenAddress);
}
},
allTakerAddressesAreNull(orders: Order[]): void {
assert.ordersHaveAtMostOneUniqueValueForProperty(orders, 'takerAddress', constants.NULL_ADDRESS);
},
allMakerAssetDatasAreErc20Token(orders: Order[], tokenAddress: string): void {
assert.ordersHaveAtMostOneUniqueValueForProperty(
orders,
'makerAssetData',
assetDataUtils.encodeERC20AssetData(tokenAddress),
);
},
allTakerAssetDatasAreErc20Token(orders: Order[], tokenAddress: string): void {
assert.ordersHaveAtMostOneUniqueValueForProperty(
orders,
'takerAssetData',
assetDataUtils.encodeERC20AssetData(tokenAddress),
);
},
/*
* Asserts that all the orders have the same value for the provided propertyName
* If the value parameter is provided, this asserts that all orders have the prope
*/
ordersHaveAtMostOneUniqueValueForProperty(orders: Order[], propertyName: string, value?: any): void {
const allValues = _.map(orders, order => _.get(order, propertyName));
sharedAssert.hasAtMostOneUniqueValue(
allValues,
`Expected all orders to have the same ${propertyName} field. Found the following ${propertyName} values: ${JSON.stringify(
allValues,
)}`,
);
if (!_.isUndefined(value)) {
const firstValue = _.head(allValues);
sharedAssert.assert(
firstValue === value,
`Expected all orders to have a ${propertyName} field with value: ${value}. Found: ${firstValue}`,
);
}
},
};

View File

@@ -0,0 +1,44 @@
import { SignedOrder } from '@0xproject/types';
import * as _ from 'lodash';
import { constants } from './constants';
export const calldataOptimizationUtils = {
/**
* Takes an array of orders and outputs an array of equivalent orders where all takerAssetData are '0x' and
* all makerAssetData are '0x' except for that of the first order, which retains its original value
* @param orders An array of SignedOrder objects
* @returns optimized orders
*/
optimizeForwarderOrders(orders: SignedOrder[]): SignedOrder[] {
const optimizedOrders = _.map(orders, (order, index) =>
transformOrder(order, {
makerAssetData: index === 0 ? order.makerAssetData : constants.NULL_BYTES,
takerAssetData: constants.NULL_BYTES,
}),
);
return optimizedOrders;
},
/**
* Takes an array of orders and outputs an array of equivalent orders where all takerAssetData are '0x' and
* all makerAssetData are '0x'
* @param orders An array of SignedOrder objects
* @returns optimized orders
*/
optimizeForwarderFeeOrders(orders: SignedOrder[]): SignedOrder[] {
const optimizedOrders = _.map(orders, (order, index) =>
transformOrder(order, {
makerAssetData: constants.NULL_BYTES,
takerAssetData: constants.NULL_BYTES,
}),
);
return optimizedOrders;
},
};
const transformOrder = (order: SignedOrder, partialOrder: Partial<SignedOrder>) => {
return {
...order,
...partialOrder,
};
};

View File

@@ -2,6 +2,7 @@ import { BigNumber } from '@0xproject/utils';
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
NULL_BYTES: '0x',
TESTRPC_NETWORK_ID: 50,
INVALID_JUMP_PATTERN: 'invalid JUMP at',
REVERT: 'revert',
@@ -10,4 +11,5 @@ export const constants = {
// tslint:disable-next-line:custom-no-magic-numbers
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
ZERO_AMOUNT: new BigNumber(0),
};

View File

@@ -0,0 +1,60 @@
import { orderFactory } from '@0xproject/order-utils';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import { assert } from '../src/utils/assert';
import { calldataOptimizationUtils } from '../src/utils/calldata_optimization_utils';
import { constants } from '../src/utils/constants';
import { chaiSetup } from './utils/chai_setup';
chaiSetup.configure();
const expect = chai.expect;
// utility for generating a set of order objects with mostly NULL values
// except for a specified makerAssetData and takerAssetData
const FAKE_ORDERS_COUNT = 5;
const generateFakeOrders = (makerAssetData: string, takerAssetData: string) =>
_.map(_.range(FAKE_ORDERS_COUNT), index => {
const order = orderFactory.createOrder(
constants.NULL_ADDRESS,
constants.ZERO_AMOUNT,
makerAssetData,
constants.ZERO_AMOUNT,
takerAssetData,
constants.NULL_ADDRESS,
);
return {
...order,
signature: 'dummy signature',
};
});
describe('calldataOptimizationUtils', () => {
const fakeMakerAssetData = 'fakeMakerAssetData';
const fakeTakerAssetData = 'fakeTakerAssetData';
const orders = generateFakeOrders(fakeMakerAssetData, fakeTakerAssetData);
describe('#optimizeForwarderOrders', () => {
it('should make makerAssetData `0x` unless first order', () => {
const optimizedOrders = calldataOptimizationUtils.optimizeForwarderOrders(orders);
expect(optimizedOrders[0].makerAssetData).to.equal(fakeMakerAssetData);
const ordersWithoutHead = _.slice(optimizedOrders, 1);
_.forEach(ordersWithoutHead, order => expect(order.makerAssetData).to.equal(constants.NULL_BYTES));
});
it('should make all takerAssetData `0x`', () => {
const optimizedOrders = calldataOptimizationUtils.optimizeForwarderOrders(orders);
_.forEach(optimizedOrders, order => expect(order.takerAssetData).to.equal(constants.NULL_BYTES));
});
});
describe('#optimizeForwarderFeeOrders', () => {
it('should make all makerAssetData `0x`', () => {
const optimizedOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(orders);
_.forEach(optimizedOrders, order => expect(order.makerAssetData).to.equal(constants.NULL_BYTES));
});
it('should make all takerAssetData `0x`', () => {
const optimizedOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(orders);
_.forEach(optimizedOrders, order => expect(order.takerAssetData).to.equal(constants.NULL_BYTES));
});
});
});

View File

@@ -277,6 +277,15 @@ describe('ExchangeWrapper', () => {
expect(orderInfo.orderHash).to.be.equal(orderHash);
});
});
describe('#getOrdersInfoAsync', () => {
it('should get the orders info', async () => {
const ordersInfo = await contractWrappers.exchange.getOrdersInfoAsync([signedOrder, anotherSignedOrder]);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
expect(ordersInfo[0].orderHash).to.be.equal(orderHash);
const anotherOrderHash = orderHashUtils.getOrderHashHex(anotherSignedOrder);
expect(ordersInfo[1].orderHash).to.be.equal(anotherOrderHash);
});
});
describe('#isValidSignature', () => {
it('should check if the signature is valid', async () => {
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
@@ -295,7 +304,7 @@ describe('ExchangeWrapper', () => {
});
});
describe('#isAllowedValidatorAsync', () => {
it('should check if the validator is alllowed', async () => {
it('should check if the validator is allowed', async () => {
const signerAddress = makerAddress;
const validatorAddress = constants.NULL_ADDRESS;
const isAllowed = await contractWrappers.exchange.isAllowedValidatorAsync(signerAddress, validatorAddress);

View File

@@ -0,0 +1,130 @@
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
import { FillScenarios } from '@0xproject/fill-scenarios';
import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
import { DoneCallback, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import * as chai from 'chai';
import { BlockParamLiteral } from 'ethereum-types';
import 'mocha';
import {
ContractWrappers,
DecodedLogEvent,
ExchangeCancelEventArgs,
ExchangeEvents,
ExchangeFillEventArgs,
OrderStatus,
} from '../src';
import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
import { tokenUtils } from './utils/token_utils';
import { provider, web3Wrapper } from './utils/web3_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('ForwarderWrapper', () => {
const contractWrappersConfig = {
networkId: constants.TESTRPC_NETWORK_ID,
blockPollingIntervalMs: 0,
};
const fillableAmount = new BigNumber(5);
const takerTokenFillAmount = new BigNumber(5);
let contractWrappers: ContractWrappers;
let fillScenarios: FillScenarios;
let forwarderContractAddress: string;
let exchangeContractAddress: string;
let zrxTokenAddress: string;
let userAddresses: string[];
let coinbase: string;
let makerAddress: string;
let takerAddress: string;
let feeRecipient: string;
let anotherMakerAddress: string;
let makerTokenAddress: string;
let takerTokenAddress: string;
let makerAssetData: string;
let takerAssetData: string;
let signedOrder: SignedOrder;
let anotherSignedOrder: SignedOrder;
before(async () => {
await blockchainLifecycle.startAsync();
contractWrappers = new ContractWrappers(provider, contractWrappersConfig);
forwarderContractAddress = contractWrappers.forwarder.getContractAddress();
exchangeContractAddress = contractWrappers.exchange.getContractAddress();
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
zrxTokenAddress = tokenUtils.getProtocolTokenAddress();
fillScenarios = new FillScenarios(
provider,
userAddresses,
zrxTokenAddress,
exchangeContractAddress,
contractWrappers.erc20Proxy.getContractAddress(),
contractWrappers.erc721Proxy.getContractAddress(),
);
[coinbase, makerAddress, takerAddress, feeRecipient, anotherMakerAddress] = userAddresses;
[makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
takerTokenAddress = tokenUtils.getWethTokenAddress();
[makerAssetData, takerAssetData] = [
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
];
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerAssetData,
takerAssetData,
makerAddress,
constants.NULL_ADDRESS,
fillableAmount,
);
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerAssetData,
takerAssetData,
makerAddress,
constants.NULL_ADDRESS,
fillableAmount,
);
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#marketBuyOrdersWithEthAsync', () => {
it('should market buy orders with eth', async () => {
const signedOrders = [signedOrder, anotherSignedOrder];
const makerAssetFillAmount = signedOrder.makerAssetAmount.plus(anotherSignedOrder.makerAssetAmount);
const txHash = await contractWrappers.forwarder.marketBuyOrdersWithEthAsync(
signedOrders,
makerAssetFillAmount,
takerAddress,
makerAssetFillAmount,
);
await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
const ordersInfo = await contractWrappers.exchange.getOrdersInfoAsync([signedOrder, anotherSignedOrder]);
expect(ordersInfo[0].orderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
expect(ordersInfo[1].orderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
});
});
describe('#marketSellOrdersWithEthAsync', () => {
it('should market sell orders with eth', async () => {
const signedOrders = [signedOrder, anotherSignedOrder];
const makerAssetFillAmount = signedOrder.makerAssetAmount.plus(anotherSignedOrder.makerAssetAmount);
const txHash = await contractWrappers.forwarder.marketSellOrdersWithEthAsync(
signedOrders,
takerAddress,
makerAssetFillAmount,
);
await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
const ordersInfo = await contractWrappers.exchange.getOrdersInfoAsync([signedOrder, anotherSignedOrder]);
expect(ordersInfo[0].orderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
expect(ordersInfo[1].orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(ordersInfo[1].orderTakerAssetFilledAmount).to.be.bignumber.equal(new BigNumber(4)); // only 95% of ETH is sold
});
});
});

View File

@@ -7,6 +7,7 @@ async callAsync(
const functionSignature = '{{this.functionSignature}}';
const inputAbi = self._lookupAbi(functionSignature).inputs;
[{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(self));
BaseContract.strictArgumentEncodingCheck(inputAbi, [{{> params inputs=inputs}}]);
const ethersFunction = self._lookupEthersInterface(functionSignature).functions.{{this.name}}(
{{> params inputs=inputs}}
) as ethers.CallDescription;

View File

@@ -11,6 +11,7 @@ public {{this.tsName}} = {
const self = this as any as {{contractName}}Contract;
const inputAbi = self._lookupAbi('{{this.functionSignature}}').inputs;
[{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(self));
BaseContract.strictArgumentEncodingCheck(inputAbi, [{{> params inputs=inputs}}]);
const encodedData = self._lookupEthersInterface('{{this.functionSignature}}').functions.{{this.name}}(
{{> params inputs=inputs}}
).data;

View File

@@ -42,12 +42,13 @@
"TestConstants",
"TestLibBytes",
"TestLibs",
"TestExchangeInternals",
"TestSignatureValidator",
"TokenRegistry",
"Validator",
"Wallet",
"Whitelist",
"WETH9",
"Whitelist",
"ZRXToken"
]
}

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "contracts",
"version": "2.1.37",
"version": "2.1.39",
"engines": {
"node": ">=6.12"
},
@@ -33,7 +33,7 @@
"lint-contracts": "solhint src/2.0.0/**/**/**/**/*.sol"
},
"config": {
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
},
"repository": {
"type": "git",
@@ -46,11 +46,11 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
"devDependencies": {
"@0xproject/abi-gen": "^1.0.2",
"@0xproject/dev-utils": "^1.0.2",
"@0xproject/sol-cov": "^1.0.2",
"@0xproject/subproviders": "^1.0.2",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/abi-gen": "^1.0.4",
"@0xproject/dev-utils": "^1.0.3",
"@0xproject/sol-cov": "^1.0.3",
"@0xproject/subproviders": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/bn.js": "^4.11.0",
"@types/ethereumjs-abi": "^0.6.0",
"@types/lodash": "4.14.104",
@@ -62,28 +62,30 @@
"copyfiles": "^1.2.0",
"dirty-chai": "^2.0.1",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solc": "^0.4.24",
"solhint": "^1.2.1",
"tslint": "5.11.0",
"typescript": "2.7.1",
"typescript": "2.9.2",
"yargs": "^10.0.3"
},
"dependencies": {
"@0xproject/base-contract": "^1.0.2",
"@0xproject/order-utils": "^1.0.1-rc.1",
"@0xproject/sol-compiler": "^1.0.2",
"@0xproject/types": "^1.0.1-rc.1",
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"@0xproject/web3-wrapper": "^1.1.0",
"@0xproject/base-contract": "^1.0.4",
"@0xproject/order-utils": "^1.0.1-rc.2",
"@0xproject/sol-compiler": "^1.0.4",
"@0xproject/types": "^1.0.1-rc.3",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"@0xproject/web3-wrapper": "^1.1.2",
"@types/js-combinatorics": "^0.5.29",
"bn.js": "^4.11.8",
"ethereum-types": "^1.0.2",
"ethereum-types": "^1.0.3",
"ethereumjs-abi": "0.6.5",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
"lodash": "^4.17.4"
"js-combinatorics": "^0.5.3",
"lodash": "^4.17.5"
}
}

View File

@@ -36,28 +36,25 @@ contract MixinAssets is
bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
/// @dev Withdraws ERC20 tokens from this contract. The contract requires a ZRX balance in order to
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
/// used to withdraw tokens that were accidentally sent to this contract.
/// @param token Address of ERC20 token to withdraw.
/// used to withdraw assets that were accidentally sent to this contract.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of ERC20 token to withdraw.
function withdrawERC20(
address token,
function withdrawAsset(
bytes assetData,
uint256 amount
)
external
onlyOwner
{
require(
IERC20Token(token).transfer(msg.sender, amount),
"WITHDRAWAL_FAILED"
);
transferAssetToSender(assetData, amount);
}
/// @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 transferPurchasedAssetToSender(
function transferAssetToSender(
bytes memory assetData,
uint256 amount
)

View File

@@ -139,7 +139,7 @@ contract MixinExchangeWrapper is
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketBuyWithWeth(
function marketBuyExactAmountWithWeth(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
bytes[] memory signatures
@@ -180,10 +180,16 @@ contract MixinExchangeWrapper is
addFillResults(totalFillResults, singleFillResults);
// Stop execution if the entire amount of makerAsset has been bought
if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
uint256 makerAssetFilledAmount = totalFillResults.makerAssetFilledAmount;
if (makerAssetFilledAmount >= makerAssetFillAmount) {
break;
}
}
require(
makerAssetFilledAmount >= makerAssetFillAmount,
"COMPLETE_FILL_FAILED"
);
return totalFillResults;
}
@@ -196,7 +202,7 @@ contract MixinExchangeWrapper is
/// @param zrxBuyAmount Desired amount of ZRX to buy.
/// @param signatures Proofs that orders have been created by makers.
/// @return totalFillResults Amounts filled and fees paid by maker and taker.
function marketBuyZrxWithWeth(
function marketBuyExactZrxWithWeth(
LibOrder.Order[] memory orders,
uint256 zrxBuyAmount,
bytes[] memory signatures
@@ -248,6 +254,10 @@ contract MixinExchangeWrapper is
}
}
require(
zrxPurchased >= zrxBuyAmount,
"COMPLETE_FILL_FAILED"
);
return totalFillResults;
}
}

View File

@@ -23,7 +23,7 @@ import "./libs/LibConstants.sol";
import "./mixins/MWeth.sol";
import "./mixins/MAssets.sol";
import "./mixins/MExchangeWrapper.sol";
import "./mixins/MForwarderCore.sol";
import "./interfaces/IForwarderCore.sol";
import "../utils/LibBytes/LibBytes.sol";
import "../protocol/Exchange/libs/LibOrder.sol";
import "../protocol/Exchange/libs/LibFillResults.sol";
@@ -37,7 +37,7 @@ contract MixinForwarderCore is
MWeth,
MAssets,
MExchangeWrapper,
MForwarderCore
IForwarderCore
{
using LibBytes for bytes;
@@ -117,7 +117,7 @@ contract MixinForwarderCore is
);
// Buy back all ZRX spent on fees.
zrxBuyAmount = orderFillResults.takerFeePaid;
feeOrderFillResults = marketBuyZrxWithWeth(
feeOrderFillResults = marketBuyExactZrxWithWeth(
feeOrders,
zrxBuyAmount,
feeSignatures
@@ -125,13 +125,6 @@ contract MixinForwarderCore is
makerAssetAmountPurchased = orderFillResults.makerAssetFilledAmount;
}
// Ensure that all ZRX fees have been repurchased and no extra WETH owned by this contract has been sold.
assertValidFillResults(
orderFillResults,
feeOrderFillResults,
zrxBuyAmount
);
// Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
// Refund remaining ETH to msg.sender.
transferEthFeeAndRefund(
@@ -142,7 +135,7 @@ contract MixinForwarderCore is
);
// Transfer purchased assets to msg.sender.
transferPurchasedAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
transferAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
}
/// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
@@ -180,7 +173,7 @@ contract MixinForwarderCore is
if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
// If the makerAsset is ZRX, it is not necessary to pay fees out of this
// contracts's ZRX balance because fees are factored into the price of the order.
orderFillResults = marketBuyZrxWithWeth(
orderFillResults = marketBuyExactZrxWithWeth(
orders,
makerAssetFillAmount,
signatures
@@ -190,14 +183,14 @@ contract MixinForwarderCore is
} else {
// Attemp to purchase desired amount of makerAsset.
// ZRX fees are payed with this contract's balance.
orderFillResults = marketBuyWithWeth(
orderFillResults = marketBuyExactAmountWithWeth(
orders,
makerAssetFillAmount,
signatures
);
// Buy back all ZRX spent on fees.
zrxBuyAmount = orderFillResults.takerFeePaid;
feeOrderFillResults = marketBuyZrxWithWeth(
feeOrderFillResults = marketBuyExactZrxWithWeth(
feeOrders,
zrxBuyAmount,
feeSignatures
@@ -205,13 +198,6 @@ contract MixinForwarderCore is
makerAssetAmountPurchased = orderFillResults.makerAssetFilledAmount;
}
// Ensure that all ZRX fees have been repurchased and no extra WETH owned by this contract has been sold.
assertValidFillResults(
orderFillResults,
feeOrderFillResults,
zrxBuyAmount
);
// Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
// Refund remaining ETH to msg.sender.
transferEthFeeAndRefund(
@@ -222,33 +208,6 @@ contract MixinForwarderCore is
);
// Transfer purchased assets to msg.sender.
transferPurchasedAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
}
/// @dev Ensures that all ZRX fees have been repurchased and no extra WETH owned by this contract has been sold.
/// @param orderFillResults Amounts filled and fees paid for primary orders.
/// @param feeOrderFillResults Amounts filled and fees paid for fee orders.
/// @param zrxBuyAmount The amount of ZRX that needed to be repurchased after filling primary orders.
function assertValidFillResults(
FillResults memory orderFillResults,
FillResults memory feeOrderFillResults,
uint256 zrxBuyAmount
)
internal
view
{
// Ensure that all ZRX spent while filling primary orders has been repurchased.
uint256 zrxPurchased = safeSub(feeOrderFillResults.makerAssetFilledAmount, feeOrderFillResults.takerFeePaid);
require(
zrxPurchased >= zrxBuyAmount,
"COMPLETE_FILL_FAILED"
);
// Ensure that no extra WETH owned by this contract has been sold.
uint256 wethSold = safeAdd(orderFillResults.takerAssetFilledAmount, feeOrderFillResults.takerAssetFilledAmount);
require(
wethSold <= msg.value,
"OVERSOLD_WETH"
);
transferAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
}
}

View File

@@ -71,12 +71,16 @@ contract MixinWeth is
"FEE_PERCENTAGE_TOO_LARGE"
);
// Calculate amount of WETH that hasn't been sold.
uint256 wethRemaining = safeSub(
msg.value,
safeAdd(wethSoldExcludingFeeOrders, wethSoldForZrx)
// Ensure that no extra WETH owned by this contract has been sold.
uint256 wethSold = safeAdd(wethSoldExcludingFeeOrders, wethSoldForZrx);
require(
wethSold <= msg.value,
"OVERSOLD_WETH"
);
// Calculate amount of WETH that hasn't been sold.
uint256 wethRemaining = safeSub(msg.value, wethSold);
// Calculate ETH fee to pay to feeRecipient.
uint256 ethFee = getPartialAmount(
feePercentage,

View File

@@ -21,13 +21,13 @@ pragma solidity 0.4.24;
contract IAssets {
/// @dev Withdraws ERC20 tokens from this contract. The contract requires a ZRX balance in order to
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
/// used to withdraw tokens that were accidentally sent to this contract.
/// @param token Address of ERC20 token to withdraw.
/// used to withdraw assets that were accidentally sent to this contract.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of ERC20 token to withdraw.
function withdrawERC20(
address token,
function withdrawAsset(
bytes assetData,
uint256 amount
)
external;

View File

@@ -28,7 +28,7 @@ contract MAssets is
/// @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 transferPurchasedAssetToSender(
function transferAssetToSender(
bytes memory assetData,
uint256 amount
)

View File

@@ -60,7 +60,7 @@ contract MExchangeWrapper {
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketBuyWithWeth(
function marketBuyExactAmountWithWeth(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
bytes[] memory signatures
@@ -77,7 +77,7 @@ contract MExchangeWrapper {
/// @param zrxBuyAmount Desired amount of ZRX to buy.
/// @param signatures Proofs that orders have been created by makers.
/// @return totalFillResults Amounts filled and fees paid by maker and taker.
function marketBuyZrxWithWeth(
function marketBuyExactZrxWithWeth(
LibOrder.Order[] memory orders,
uint256 zrxBuyAmount,
bytes[] memory signatures

View File

@@ -1,42 +0,0 @@
/*
Copyright 2018 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.4.24;
pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/libs/LibOrder.sol";
import "../../protocol/Exchange/libs/LibFillResults.sol";
import "../interfaces/IForwarderCore.sol";
contract MForwarderCore is
IForwarderCore
{
/// @dev Ensures that all ZRX fees have been repurchased and no extra WETH owned by this contract has been sold.
/// @param orderFillResults Amounts filled and fees paid for primary orders.
/// @param feeOrderFillResults Amounts filled and fees paid for fee orders.
/// @param zrxBuyAmount The amount of ZRX that needed to be repurchased after filling primary orders.
function assertValidFillResults(
LibFillResults.FillResults memory orderFillResults,
LibFillResults.FillResults memory feeOrderFillResults,
uint256 zrxBuyAmount
)
internal
view;
}

View File

@@ -207,7 +207,6 @@ contract MixinExchangeCore is
/// @param order that was filled.
/// @param takerAddress Address of taker who filled the order.
/// @param orderTakerAssetFilledAmount Amount of order already filled.
/// @return fillResults Amounts filled and fees paid by maker and taker.
function updateFilledState(
Order memory order,
address takerAddress,

View File

@@ -96,14 +96,15 @@ contract MixinSignatureValidator is
"LENGTH_GREATER_THAN_0_REQUIRED"
);
// Ensure signature is supported
// Pop last byte off of signature byte array.
uint8 signatureTypeRaw = uint8(signature.popLastByte());
// Ensure signature is supported
require(
signatureTypeRaw < uint8(SignatureType.NSignatureTypes),
"SIGNATURE_UNSUPPORTED"
);
// Pop last byte off of signature byte array.
SignatureType signatureType = SignatureType(signatureTypeRaw);
// Variables are not scoped in Solidity.
@@ -141,7 +142,12 @@ contract MixinSignatureValidator is
v = uint8(signature[0]);
r = signature.readBytes32(1);
s = signature.readBytes32(33);
recovered = ecrecover(hash, v, r, s);
recovered = ecrecover(
hash,
v,
r,
s
);
isValid = signerAddress == recovered;
return isValid;
@@ -197,7 +203,6 @@ contract MixinSignatureValidator is
// | 0x14 + x | 1 | Signature type is always "\x06" |
} else if (signatureType == SignatureType.Validator) {
// Pop last 20 bytes off of signature byte array.
address validatorAddress = signature.popLast20Bytes();
// Ensure signer has approved validator.

View File

@@ -123,22 +123,25 @@ contract MixinTransactions is
bytes32 dataHash = keccak256(data);
// Assembly for more efficiently computing:
// keccak256(abi.encode(
// keccak256(abi.encodePacked(
// EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,
// salt,
// signerAddress,
// bytes32(signerAddress),
// keccak256(data)
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, schemaHash)
mstore(add(memPtr, 32), salt)
mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(memPtr, 96), dataHash)
mstore(memPtr, schemaHash) // hash of schema
mstore(add(memPtr, 32), salt) // salt
mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress
mstore(add(memPtr, 96), dataHash) // hash of data
// Compute hash
result := keccak256(memPtr, 128)
}
return result;
}

View File

@@ -24,20 +24,17 @@ import "./LibOrder.sol";
contract LibAbiEncoder {
/// @dev ABI encodes calldata for `fillOrder` in memory and returns the address range.
/// This range can be passed into `call` or `delegatecall` to invoke an external
/// call to `fillOrder`.
/// @dev ABI encodes calldata for `fillOrder`.
/// @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 calldataBegin Memory address of ABI encoded calldata.
/// @return calldataLength Lenfgth of ABI encoded calldata.
/// @return ABI encoded calldata for `fillOrder`.
function abiEncodeFillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
public
internal
pure
returns (bytes memory fillOrderCalldata)
{
@@ -207,10 +204,10 @@ contract LibAbiEncoder {
}
// Set length of calldata
mstore(
fillOrderCalldata,
sub(dataAreaEnd, add(fillOrderCalldata, 0x20))
)
mstore(fillOrderCalldata, sub(dataAreaEnd, add(fillOrderCalldata, 0x20)))
// Increment free memory pointer
mstore(0x40, dataAreaEnd)
}
return fillOrderCalldata;

View File

@@ -30,7 +30,7 @@ contract LibEIP712 {
string constant internal EIP712_DOMAIN_VERSION = "2";
// Hash of the EIP712 Domain Separator Schema
bytes32 public constant EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
"EIP712Domain(",
"string name,",
"string version,",
@@ -45,11 +45,11 @@ contract LibEIP712 {
constructor ()
public
{
EIP712_DOMAIN_HASH = keccak256(abi.encode(
EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
keccak256(bytes(EIP712_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)),
address(this)
bytes32(address(this))
));
}
@@ -59,8 +59,28 @@ contract LibEIP712 {
function hashEIP712Message(bytes32 hashStruct)
internal
view
returns (bytes32)
returns (bytes32 result)
{
return keccak256(abi.encodePacked(EIP191_HEADER, EIP712_DOMAIN_HASH, hashStruct));
bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;
// Assembly for more efficient computing:
// keccak256(abi.encodePacked(
// EIP191_HEADER,
// EIP712_DOMAIN_HASH,
// hashStruct
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
mstore(add(memPtr, 34), hashStruct) // Hash of struct
// Compute hash
result := keccak256(memPtr, 66)
}
return result;
}
}

View File

@@ -103,11 +103,12 @@ contract LibOrder is
bytes32 takerAssetDataHash = keccak256(order.takerAssetData);
// Assembly for more efficiently computing:
// keccak256(abi.encode(
// order.makerAddress,
// order.takerAddress,
// order.feeRecipientAddress,
// order.senderAddress,
// keccak256(abi.encodePacked(
// EIP712_ORDER_SCHEMA_HASH,
// bytes32(order.makerAddress),
// bytes32(order.takerAddress),
// bytes32(order.feeRecipientAddress),
// bytes32(order.senderAddress),
// order.makerAssetAmount,
// order.takerAssetAmount,
// order.makerFee,
@@ -119,24 +120,26 @@ contract LibOrder is
// ));
assembly {
// Calculate memory addresses that will be swapped out before hashing
let pos1 := sub(order, 32)
let pos2 := add(order, 320)
let pos3 := add(order, 352)
// Backup
// solhint-disable-next-line space-after-comma
let temp1 := mload(sub(order, 32))
let temp2 := mload(add(order, 320))
let temp3 := mload(add(order, 352))
let temp1 := mload(pos1)
let temp2 := mload(pos2)
let temp3 := mload(pos3)
// Hash in place
// solhint-disable-next-line space-after-comma
mstore(sub(order, 32), schemaHash)
mstore(add(order, 320), makerAssetDataHash)
mstore(add(order, 352), takerAssetDataHash)
result := keccak256(sub(order, 32), 416)
mstore(pos1, schemaHash)
mstore(pos2, makerAssetDataHash)
mstore(pos3, takerAssetDataHash)
result := keccak256(pos1, 416)
// Restore
// solhint-disable-next-line space-after-comma
mstore(sub(order, 32), temp1)
mstore(add(order, 320), temp2)
mstore(add(order, 352), temp3)
mstore(pos1, temp1)
mstore(pos2, temp2)
mstore(pos3, temp3)
}
return result;
}

View File

@@ -0,0 +1,121 @@
/*
Copyright 2018 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.4.24;
pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/Exchange.sol";
// solhint-disable no-empty-blocks
contract TestExchangeInternals is
Exchange
{
constructor ()
public
Exchange("")
{}
/// @dev Adds properties of both FillResults instances.
/// Modifies the first FillResults instance specified.
/// Note that this function has been modified from the original
// internal version to return the FillResults.
/// @param totalFillResults Fill results instance that will be added onto.
/// @param singleFillResults Fill results instance that will be added to totalFillResults.
/// @return newTotalFillResults The result of adding singleFillResults to totalFilResults.
function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
public
pure
returns (FillResults memory)
{
addFillResults(totalFillResults, singleFillResults);
return totalFillResults;
}
/// @dev Calculates amounts filled and fees paid by maker and taker.
/// @param order to be filled.
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
/// @return fillResults Amounts filled and fees paid by maker and taker.
function publicCalculateFillResults(
Order memory order,
uint256 takerAssetFilledAmount
)
public
pure
returns (FillResults memory fillResults)
{
return calculateFillResults(order, takerAssetFilledAmount);
}
/// @dev Calculates partial value given a numerator and denominator.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return Partial value of target.
function publicGetPartialAmount(
uint256 numerator,
uint256 denominator,
uint256 target
)
public
pure
returns (uint256 partialAmount)
{
return getPartialAmount(numerator, denominator, target);
}
/// @dev Checks if rounding error > 0.1%.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to multiply with numerator/denominator.
/// @return Rounding error is present.
function publicIsRoundingError(
uint256 numerator,
uint256 denominator,
uint256 target
)
public
pure
returns (bool isError)
{
return isRoundingError(numerator, denominator, target);
}
/// @dev Updates state with results of a fill order.
/// @param order that was filled.
/// @param takerAddress Address of taker who filled the order.
/// @param orderTakerAssetFilledAmount Amount of order already filled.
/// @return fillResults Amounts filled and fees paid by maker and taker.
function publicUpdateFilledState(
Order memory order,
address takerAddress,
bytes32 orderHash,
uint256 orderTakerAssetFilledAmount,
FillResults memory fillResults
)
public
{
updateFilledState(
order,
takerAddress,
orderHash,
orderTakerAssetFilledAmount,
fillResults
);
}
}

View File

@@ -22,13 +22,33 @@ pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/libs/LibMath.sol";
import "../../protocol/Exchange/libs/LibOrder.sol";
import "../../protocol/Exchange/libs/LibFillResults.sol";
import "../../protocol/Exchange/libs/LibAbiEncoder.sol";
contract TestLibs is
LibMath,
LibOrder,
LibFillResults
LibFillResults,
LibAbiEncoder
{
function publicAbiEncodeFillOrder(
Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
public
pure
returns (bytes memory fillOrderCalldata)
{
fillOrderCalldata = abiEncodeFillOrder(
order,
takerAssetFillAmount,
signature
);
return fillOrderCalldata;
}
function publicGetPartialAmount(
uint256 numerator,
uint256 denominator,

View File

@@ -2,7 +2,10 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils';
import * as _ from 'lodash';
import { chaiSetup } from '../utils/chai_setup';
import { CoreCombinatorialUtils, coreCombinatorialUtilsFactoryAsync } from '../utils/core_combinatorial_utils';
import {
FillOrderCombinatorialUtils,
fillOrderCombinatorialUtilsFactoryAsync,
} from '../utils/fill_order_combinatorial_utils';
import {
AllowanceAmountScenario,
AssetDataScenario,
@@ -47,11 +50,11 @@ const defaultFillScenario = {
};
describe('FillOrder Tests', () => {
let coreCombinatorialUtils: CoreCombinatorialUtils;
let fillOrderCombinatorialUtils: FillOrderCombinatorialUtils;
before(async () => {
await blockchainLifecycle.startAsync();
coreCombinatorialUtils = await coreCombinatorialUtilsFactoryAsync(web3Wrapper, txDefaults);
fillOrderCombinatorialUtils = await fillOrderCombinatorialUtilsFactoryAsync(web3Wrapper, txDefaults);
});
after(async () => {
await blockchainLifecycle.revertAsync();
@@ -67,19 +70,19 @@ describe('FillOrder Tests', () => {
_.forEach(fillScenarios, fillScenario => {
const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`;
it(description, async () => {
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
});
};
const allFillScenarios = CoreCombinatorialUtils.generateFillOrderCombinations();
const allFillScenarios = FillOrderCombinatorialUtils.generateFillOrderCombinations();
describe('Combinatorially generated fills orders', () => test(allFillScenarios));
it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
const fillScenario = {
...defaultFillScenario,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
const fillScenario = {
@@ -89,7 +92,7 @@ describe('FillOrder Tests', () => {
takerAssetAmountScenario: OrderAssetAmountScenario.Small,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
const fillScenario = {
@@ -99,7 +102,7 @@ describe('FillOrder Tests', () => {
makerAssetAmountScenario: OrderAssetAmountScenario.Small,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
const fillScenario = {
@@ -109,14 +112,14 @@ describe('FillOrder Tests', () => {
takerScenario: TakerScenario.CorrectlySpecified,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => {
const fillScenario = {
...defaultFillScenario,
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw when taker is specified and order is claimed by other', async () => {
const fillScenario = {
@@ -126,7 +129,7 @@ describe('FillOrder Tests', () => {
takerScenario: TakerScenario.IncorrectlySpecified,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if makerAssetAmount is 0', async () => {
@@ -138,7 +141,7 @@ describe('FillOrder Tests', () => {
},
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if takerAssetAmount is 0', async () => {
@@ -150,7 +153,7 @@ describe('FillOrder Tests', () => {
},
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if takerAssetFillAmount is 0', async () => {
@@ -158,7 +161,7 @@ describe('FillOrder Tests', () => {
...defaultFillScenario,
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.Zero,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if an order is expired', async () => {
@@ -169,7 +172,7 @@ describe('FillOrder Tests', () => {
expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if maker erc20Balances are too low to fill order', async () => {
@@ -180,7 +183,7 @@ describe('FillOrder Tests', () => {
traderAssetBalance: BalanceAmountScenario.TooLow,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if taker erc20Balances are too low to fill order', async () => {
@@ -191,7 +194,7 @@ describe('FillOrder Tests', () => {
traderAssetBalance: BalanceAmountScenario.TooLow,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if maker allowances are too low to fill order', async () => {
@@ -202,7 +205,7 @@ describe('FillOrder Tests', () => {
traderAssetAllowance: AllowanceAmountScenario.TooLow,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should throw if taker allowances are too low to fill order', async () => {
@@ -213,7 +216,7 @@ describe('FillOrder Tests', () => {
traderAssetAllowance: AllowanceAmountScenario.TooLow,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
});
@@ -228,7 +231,7 @@ describe('FillOrder Tests', () => {
},
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => {
@@ -241,7 +244,7 @@ describe('FillOrder Tests', () => {
},
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario, true);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario, true);
});
it('should successfully fill order when makerAsset is ERC20 and takerAsset is ERC721', async () => {
@@ -254,7 +257,7 @@ describe('FillOrder Tests', () => {
},
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should successfully fill order when makerAsset is ERC721 and approveAll is set for it', async () => {
@@ -271,7 +274,7 @@ describe('FillOrder Tests', () => {
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
it('should successfully fill order when makerAsset and takerAsset are ERC721 and approveAll is set for them', async () => {
@@ -292,7 +295,7 @@ describe('FillOrder Tests', () => {
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
},
};
await coreCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
});
});

View File

@@ -0,0 +1,305 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { Order, RevertReason, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import { TestExchangeInternalsContract } from '../../generated_contract_wrappers/test_exchange_internals';
import { artifacts } from '../utils/artifacts';
import {
getInvalidOpcodeErrorMessageForCallAsync,
getRevertReasonOrErrorMessageForSendTransactionAsync,
} from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { bytes32Values, testCombinatoriallyWithReferenceFuncAsync, uint256Values } from '../utils/combinatorial_utils';
import { constants } from '../utils/constants';
import { FillResults } from '../utils/types';
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
chaiSetup.configure();
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
const emptyOrder: Order = {
senderAddress: constants.NULL_ADDRESS,
makerAddress: constants.NULL_ADDRESS,
takerAddress: constants.NULL_ADDRESS,
makerFee: new BigNumber(0),
takerFee: new BigNumber(0),
makerAssetAmount: new BigNumber(0),
takerAssetAmount: new BigNumber(0),
makerAssetData: '0x',
takerAssetData: '0x',
salt: new BigNumber(0),
exchangeAddress: constants.NULL_ADDRESS,
feeRecipientAddress: constants.NULL_ADDRESS,
expirationTimeSeconds: new BigNumber(0),
};
const emptySignedOrder: SignedOrder = {
...emptyOrder,
signature: '',
};
const overflowErrorForCall = new Error(RevertReason.Uint256Overflow);
async function referenceGetPartialAmountAsync(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): Promise<BigNumber> {
const invalidOpcodeErrorForCall = new Error(await getInvalidOpcodeErrorMessageForCallAsync());
const product = numerator.mul(target);
if (product.greaterThan(MAX_UINT256)) {
throw overflowErrorForCall;
}
if (denominator.eq(0)) {
throw invalidOpcodeErrorForCall;
}
return product.dividedToIntegerBy(denominator);
}
describe('Exchange core internal functions', () => {
let testExchange: TestExchangeInternalsContract;
let invalidOpcodeErrorForCall: Error | undefined;
let overflowErrorForSendTransaction: Error | undefined;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
artifacts.TestExchangeInternals,
provider,
txDefaults,
);
overflowErrorForSendTransaction = new Error(
await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow),
);
invalidOpcodeErrorForCall = new Error(await getInvalidOpcodeErrorMessageForCallAsync());
});
// Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
// the blockchain state for any tests which modify it!
describe('addFillResults', async () => {
function makeFillResults(value: BigNumber): FillResults {
return {
makerAssetFilledAmount: value,
takerAssetFilledAmount: value,
makerFeePaid: value,
takerFeePaid: value,
};
}
async function referenceAddFillResultsAsync(
totalValue: BigNumber,
singleValue: BigNumber,
): Promise<FillResults> {
// Note(albrow): Here, each of totalFillResults and
// singleFillResults will consist of fields with the same values.
// This should be safe because none of the fields in a given
// FillResults are ever used together in a mathemetical operation.
// They are only used with the corresponding field from *the other*
// FillResults, which are different.
const totalFillResults = makeFillResults(totalValue);
const singleFillResults = makeFillResults(singleValue);
// HACK(albrow): _.mergeWith mutates the first argument! To
// workaround this we use _.cloneDeep.
return _.mergeWith(
_.cloneDeep(totalFillResults),
singleFillResults,
(totalVal: BigNumber, singleVal: BigNumber) => {
const newTotal = totalVal.add(singleVal);
if (newTotal.greaterThan(MAX_UINT256)) {
throw overflowErrorForCall;
}
return newTotal;
},
);
}
async function testAddFillResultsAsync(totalValue: BigNumber, singleValue: BigNumber): Promise<FillResults> {
const totalFillResults = makeFillResults(totalValue);
const singleFillResults = makeFillResults(singleValue);
return testExchange.publicAddFillResults.callAsync(totalFillResults, singleFillResults);
}
await testCombinatoriallyWithReferenceFuncAsync(
'addFillResults',
referenceAddFillResultsAsync,
testAddFillResultsAsync,
[uint256Values, uint256Values],
);
});
describe('calculateFillResults', async () => {
function makeOrder(
makerAssetAmount: BigNumber,
takerAssetAmount: BigNumber,
makerFee: BigNumber,
takerFee: BigNumber,
): Order {
return {
...emptyOrder,
makerAssetAmount,
takerAssetAmount,
makerFee,
takerFee,
};
}
async function referenceCalculateFillResultsAsync(
orderTakerAssetAmount: BigNumber,
takerAssetFilledAmount: BigNumber,
otherAmount: BigNumber,
): Promise<FillResults> {
// Note(albrow): Here we are re-using the same value (otherAmount)
// for order.makerAssetAmount, order.makerFee, and order.takerFee.
// This should be safe because they are never used with each other
// in any mathematical operation in either the reference TypeScript
// implementation or the Solidity implementation of
// calculateFillResults.
return {
makerAssetFilledAmount: await referenceGetPartialAmountAsync(
takerAssetFilledAmount,
orderTakerAssetAmount,
otherAmount,
),
takerAssetFilledAmount,
makerFeePaid: await referenceGetPartialAmountAsync(
takerAssetFilledAmount,
orderTakerAssetAmount,
otherAmount,
),
takerFeePaid: await referenceGetPartialAmountAsync(
takerAssetFilledAmount,
orderTakerAssetAmount,
otherAmount,
),
};
}
async function testCalculateFillResultsAsync(
orderTakerAssetAmount: BigNumber,
takerAssetFilledAmount: BigNumber,
otherAmount: BigNumber,
): Promise<FillResults> {
const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
return testExchange.publicCalculateFillResults.callAsync(order, takerAssetFilledAmount);
}
await testCombinatoriallyWithReferenceFuncAsync(
'calculateFillResults',
referenceCalculateFillResultsAsync,
testCalculateFillResultsAsync,
[uint256Values, uint256Values, uint256Values],
);
});
describe('getPartialAmount', async () => {
async function testGetPartialAmountAsync(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): Promise<BigNumber> {
return testExchange.publicGetPartialAmount.callAsync(numerator, denominator, target);
}
await testCombinatoriallyWithReferenceFuncAsync(
'getPartialAmount',
referenceGetPartialAmountAsync,
testGetPartialAmountAsync,
[uint256Values, uint256Values, uint256Values],
);
});
describe('isRoundingError', async () => {
async function referenceIsRoundingErrorAsync(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): Promise<boolean> {
const product = numerator.mul(target);
if (denominator.eq(0)) {
throw invalidOpcodeErrorForCall;
}
const remainder = product.mod(denominator);
if (remainder.eq(0)) {
return false;
}
if (product.greaterThan(MAX_UINT256)) {
throw overflowErrorForCall;
}
if (product.eq(0)) {
throw invalidOpcodeErrorForCall;
}
const remainderTimes1000000 = remainder.mul('1000000');
if (remainderTimes1000000.greaterThan(MAX_UINT256)) {
throw overflowErrorForCall;
}
const errPercentageTimes1000000 = remainderTimes1000000.dividedToIntegerBy(product);
return errPercentageTimes1000000.greaterThan('1000');
}
async function testIsRoundingErrorAsync(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): Promise<boolean> {
return testExchange.publicIsRoundingError.callAsync(numerator, denominator, target);
}
await testCombinatoriallyWithReferenceFuncAsync(
'isRoundingError',
referenceIsRoundingErrorAsync,
testIsRoundingErrorAsync,
[uint256Values, uint256Values, uint256Values],
);
});
describe('updateFilledState', async () => {
// Note(albrow): Since updateFilledState modifies the state by calling
// sendTransaction, we must reset the state after each test.
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
async function referenceUpdateFilledStateAsync(
takerAssetFilledAmount: BigNumber,
orderTakerAssetFilledAmount: BigNumber,
// tslint:disable-next-line:no-unused-variable
orderHash: string,
): Promise<BigNumber> {
const totalFilledAmount = takerAssetFilledAmount.add(orderTakerAssetFilledAmount);
if (totalFilledAmount.greaterThan(MAX_UINT256)) {
throw overflowErrorForSendTransaction;
}
return totalFilledAmount;
}
async function testUpdateFilledStateAsync(
takerAssetFilledAmount: BigNumber,
orderTakerAssetFilledAmount: BigNumber,
orderHash: string,
): Promise<BigNumber> {
const fillResults = {
makerAssetFilledAmount: new BigNumber(0),
takerAssetFilledAmount,
makerFeePaid: new BigNumber(0),
takerFeePaid: new BigNumber(0),
};
await web3Wrapper.awaitTransactionSuccessAsync(
await testExchange.publicUpdateFilledState.sendTransactionAsync(
emptySignedOrder,
constants.NULL_ADDRESS,
orderHash,
orderTakerAssetFilledAmount,
fillResults,
),
constants.AWAIT_TRANSACTION_MINED_MS,
);
return testExchange.filled.callAsync(orderHash);
}
await testCombinatoriallyWithReferenceFuncAsync(
'updateFilledState',
referenceUpdateFilledStateAsync,
testUpdateFilledStateAsync,
[uint256Values, uint256Values, bytes32Values],
);
});
});

View File

@@ -67,6 +67,35 @@ describe('Exchange libs', () => {
});
});
});
// Note(albrow): These tests are designed to be supplemental to the
// combinatorial tests in test/exchange/internal. They test specific edge
// cases that are not covered by the combinatorial tests.
describe('LibMath', () => {
it('should return false if there is a rounding error of 0.1%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(999);
const target = new BigNumber(50);
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
it('should return false if there is a rounding of 0.09%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(9991);
const target = new BigNumber(500);
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
it('should return true if there is a rounding error of 0.11%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(9989);
const target = new BigNumber(500);
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.true();
});
});
describe('LibOrder', () => {
describe('getOrderSchema', () => {
@@ -93,96 +122,4 @@ describe('Exchange libs', () => {
});
});
});
describe('LibMath', () => {
describe('isRoundingError', () => {
it('should return false if there is a rounding error of 0.1%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(999);
const target = new BigNumber(50);
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
it('should return false if there is a rounding of 0.09%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(9991);
const target = new BigNumber(500);
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
it('should return true if there is a rounding error of 0.11%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(9989);
const target = new BigNumber(500);
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.true();
});
it('should return true if there is a rounding error > 0.1%', async () => {
const numerator = new BigNumber(3);
const denominator = new BigNumber(7);
const target = new BigNumber(10);
// rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.true();
});
it('should return false when there is no rounding error', async () => {
const numerator = new BigNumber(1);
const denominator = new BigNumber(2);
const target = new BigNumber(10);
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
it('should return false when there is rounding error <= 0.1%', async () => {
// randomly generated numbers
const numerator = new BigNumber(76564);
const denominator = new BigNumber(676373677);
const target = new BigNumber(105762562);
// rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) /
// (76564*105762562/676373677) = 0.0007%
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
});
describe('getPartialAmount', () => {
it('should return the numerator/denominator*target', async () => {
const numerator = new BigNumber(1);
const denominator = new BigNumber(2);
const target = new BigNumber(10);
const partialAmount = await libs.publicGetPartialAmount.callAsync(numerator, denominator, target);
const expectedPartialAmount = 5;
expect(partialAmount).to.be.bignumber.equal(expectedPartialAmount);
});
it('should round down', async () => {
const numerator = new BigNumber(2);
const denominator = new BigNumber(3);
const target = new BigNumber(10);
const partialAmount = await libs.publicGetPartialAmount.callAsync(numerator, denominator, target);
const expectedPartialAmount = 6;
expect(partialAmount).to.be.bignumber.equal(expectedPartialAmount);
});
it('should round .5 down', async () => {
const numerator = new BigNumber(1);
const denominator = new BigNumber(20);
const target = new BigNumber(10);
const partialAmount = await libs.publicGetPartialAmount.callAsync(numerator, denominator, target);
const expectedPartialAmount = 0;
expect(partialAmount).to.be.bignumber.equal(expectedPartialAmount);
});
});
});
});

View File

@@ -69,13 +69,22 @@ describe('matchOrders', () => {
before(async () => {
// Create accounts
const accounts = await web3Wrapper.getAvailableAddressesAsync();
// Hack(albrow): Both Prettier and TSLint insert a trailing comma below
// but that is invalid syntax as of TypeScript version >= 2.8. We don't
// have the right fine-grained configuration options in TSLint,
// Prettier, or TypeScript, to reconcile this, so we will just have to
// wait for them to sort it out. We disable TSLint and Prettier for
// this part of the code for now. This occurs several times in this
// file. See https://github.com/prettier/prettier/issues/4624.
// prettier-ignore
const usedAddresses = ([
owner,
makerAddressLeft,
makerAddressRight,
takerAddress,
feeRecipientAddressLeft,
feeRecipientAddressRight,
// tslint:disable-next-line:trailing-comma
feeRecipientAddressRight
] = _.slice(accounts, 0, 6));
// Create wrappers
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
@@ -201,9 +210,11 @@ describe('matchOrders', () => {
// Match signedOrderLeft with signedOrderRight
let newERC20BalancesByOwner: ERC20BalancesByOwner;
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
// prettier-ignore
[
newERC20BalancesByOwner,
newERC721TokenIdsByOwner,
// tslint:disable-next-line:trailing-comma
newERC721TokenIdsByOwner
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
signedOrderLeft,
signedOrderRight,
@@ -306,9 +317,11 @@ describe('matchOrders', () => {
// Match orders
let newERC20BalancesByOwner: ERC20BalancesByOwner;
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
// prettier-ignore
[
newERC20BalancesByOwner,
newERC721TokenIdsByOwner,
// tslint:disable-next-line:trailing-comma
newERC721TokenIdsByOwner
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
signedOrderLeft,
signedOrderRight,
@@ -374,9 +387,11 @@ describe('matchOrders', () => {
// Match orders
let newERC20BalancesByOwner: ERC20BalancesByOwner;
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
// prettier-ignore
[
newERC20BalancesByOwner,
newERC721TokenIdsByOwner,
// tslint:disable-next-line:trailing-comma
newERC721TokenIdsByOwner
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
signedOrderLeft,
signedOrderRight,

View File

@@ -1,6 +1,6 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { addSignedMessagePrefix, assetDataUtils, MessagePrefixType, orderHashUtils } from '@0xproject/order-utils';
import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types';
import { addSignedMessagePrefix, assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
import { RevertReason, SignatureType, SignedOrder, SignerType } from '@0xproject/types';
import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types';
import ethUtil = require('ethereumjs-util');
@@ -113,7 +113,7 @@ describe('MixinSignatureValidator', () => {
it('should revert when signature type is unsupported', async () => {
const unsupportedSignatureType = SignatureType.NSignatureTypes;
const unsupportedSignatureHex = `0x${unsupportedSignatureType}`;
const unsupportedSignatureHex = '0x' + Buffer.from([unsupportedSignatureType]).toString('hex');
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
return expectContractCallFailed(
signatureValidator.publicIsValidSignature.callAsync(
@@ -126,7 +126,7 @@ describe('MixinSignatureValidator', () => {
});
it('should revert when SignatureType=Illegal', async () => {
const unsupportedSignatureHex = `0x${SignatureType.Illegal}`;
const unsupportedSignatureHex = '0x' + Buffer.from([SignatureType.Illegal]).toString('hex');
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
return expectContractCallFailed(
signatureValidator.publicIsValidSignature.callAsync(
@@ -139,7 +139,7 @@ describe('MixinSignatureValidator', () => {
});
it('should return false when SignatureType=Invalid and signature has a length of zero', async () => {
const signatureHex = `0x${SignatureType.Invalid}`;
const signatureHex = '0x' + Buffer.from([SignatureType.Invalid]).toString('hex');
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
orderHashHex,
@@ -213,7 +213,7 @@ describe('MixinSignatureValidator', () => {
it('should return true when SignatureType=EthSign and signature is valid', async () => {
// Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.EthSign);
const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, SignerType.Default);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature
@@ -236,7 +236,7 @@ describe('MixinSignatureValidator', () => {
it('should return false when SignatureType=EthSign and signature is invalid', async () => {
// Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.EthSign);
const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, SignerType.Default);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature
@@ -385,7 +385,7 @@ describe('MixinSignatureValidator', () => {
it('should return true when SignatureType=Trezor and signature is valid', async () => {
// Create Trezor signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.Trezor);
const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, SignerType.Trezor);
const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey);
// Create 0x signature from Trezor signature
@@ -408,7 +408,7 @@ describe('MixinSignatureValidator', () => {
it('should return false when SignatureType=Trezor and signature is invalid', async () => {
// Create Trezor signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.Trezor);
const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, SignerType.Trezor);
const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey);
// Create 0x signature from Trezor signature

View File

@@ -36,6 +36,7 @@ describe(ContractName.Forwarder, () => {
let feeRecipientAddress: string;
let otherAddress: string;
let defaultMakerAssetAddress: string;
let zrxAssetData: string;
let weth: DummyERC20TokenContract;
let zrxToken: DummyERC20TokenContract;
@@ -90,7 +91,7 @@ describe(ContractName.Forwarder, () => {
erc20Wrapper.addDummyTokenContract(weth);
const wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
artifacts.Exchange,
provider,
@@ -722,25 +723,18 @@ describe(ContractName.Forwarder, () => {
);
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should not change balances if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
const ordersWithoutFee = [orderWithoutFee];
const feeOrders: SignedOrder[] = [];
const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(4);
tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
value: ethValue,
from: takerAddress,
});
const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
const newBalances = await erc20Wrapper.getBalancesAsync();
const totalEthSpent = gasPrice.times(tx.gasUsed);
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
expect(newBalances).to.deep.equal(erc20Balances);
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
return expectTransactionFailedAsync(
forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
value: ethValue,
from: takerAddress,
}),
RevertReason.CompleteFillFailed,
);
});
it('should buy an ERC721 asset from a single order', async () => {
const makerAssetId = erc721MakerAssetIds[0];
@@ -775,7 +769,7 @@ describe(ContractName.Forwarder, () => {
);
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should buy an ERC721 asset and ignore later orders with different makerAssetData', async () => {
it('should revert if buying an ERC721 asset when later orders contain different makerAssetData', async () => {
const makerAssetId = erc721MakerAssetIds[0];
orderWithoutFee = await orderFactory.newSignedOrderAsync({
makerAssetAmount: new BigNumber(1),
@@ -786,33 +780,12 @@ describe(ContractName.Forwarder, () => {
const feeOrders: SignedOrder[] = [];
const makerAssetFillAmount = new BigNumber(1).plus(differentMakerAssetDataOrder.makerAssetAmount);
const ethValue = orderWithFee.takerAssetAmount;
tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
from: takerAddress,
value: ethValue,
});
const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
const newBalances = await erc20Wrapper.getBalancesAsync();
const primaryTakerAssetFillAmount = ethValue;
const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
expect(newOwner).to.be.bignumber.equal(takerAddress);
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
);
expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
constants.ZERO_AMOUNT,
);
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
erc20Balances[makerAddress][defaultMakerAssetAddress],
);
expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
erc20Balances[takerAddress][defaultMakerAssetAddress],
return expectTransactionFailedAsync(
forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
value: ethValue,
from: takerAddress,
}),
RevertReason.CompleteFillFailed,
);
});
it('should buy an ERC721 asset and pay ZRX fees from a single fee order', async () => {
@@ -998,6 +971,26 @@ describe(ContractName.Forwarder, () => {
);
});
});
describe('withdrawAsset', () => {
it('should allow owner to withdraw ERC20 tokens', async () => {
const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address];
await forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: owner });
const newBalances = await erc20Wrapper.getBalancesAsync();
expect(newBalances[owner][zrxToken.address]).to.be.bignumber.equal(
erc20Balances[owner][zrxToken.address].plus(zrxWithdrawAmount),
);
expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal(
erc20Balances[forwarderContract.address][zrxToken.address].minus(zrxWithdrawAmount),
);
});
it('should revert if not called by owner', async () => {
const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address];
await expectTransactionFailedAsync(
forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: makerAddress }),
RevertReason.OnlyContractOwner,
);
});
});
});
// tslint:disable:max-file-line-count
// tslint:enable:no-unnecessary-type-assertion

View File

@@ -16,6 +16,7 @@ import * as MultiSigWalletWithTimeLock from '../../artifacts/MultiSigWalletWithT
import * as TestAssetProxyDispatcher from '../../artifacts/TestAssetProxyDispatcher.json';
import * as TestAssetProxyOwner from '../../artifacts/TestAssetProxyOwner.json';
import * as TestConstants from '../../artifacts/TestConstants.json';
import * as TestExchangeInternals from '../../artifacts/TestExchangeInternals.json';
import * as TestLibBytes from '../../artifacts/TestLibBytes.json';
import * as TestLibs from '../../artifacts/TestLibs.json';
import * as TestSignatureValidator from '../../artifacts/TestSignatureValidator.json';
@@ -46,6 +47,7 @@ export const artifacts = {
TestConstants: (TestConstants as any) as ContractArtifact,
TestLibBytes: (TestLibBytes as any) as ContractArtifact,
TestLibs: (TestLibs as any) as ContractArtifact,
TestExchangeInternals: (TestExchangeInternals as any) as ContractArtifact,
TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact,
Validator: (Validator as any) as ContractArtifact,
Wallet: (Wallet as any) as ContractArtifact,

View File

@@ -15,6 +15,14 @@ let nodeType: NodeType | undefined;
// resolve with either a transaction receipt or a transaction hash.
export type sendTransactionResult = Promise<TransactionReceipt | TransactionReceiptWithDecodedLogs | string>;
/**
* Returns ganacheError if the backing Ethereum node is Ganache and gethError
* if it is Geth.
* @param ganacheError the error to be returned if the backing node is Ganache.
* @param gethError the error to be returned if the backing node is Geth.
* @returns either the given ganacheError or gethError depending on the backing
* node.
*/
async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise<string> {
if (_.isUndefined(nodeType)) {
nodeType = await web3Wrapper.getNodeTypeAsync();
@@ -41,6 +49,25 @@ async function _getContractCallFailedErrorMessageAsync(): Promise<string> {
return _getGanacheOrGethError('revert', 'Contract call failed');
}
/**
* Returns the expected error message for an 'invalid opcode' resulting from a
* contract call. The exact error message depends on the backing Ethereum node.
*/
export async function getInvalidOpcodeErrorMessageForCallAsync(): Promise<string> {
return _getGanacheOrGethError('invalid opcode', 'Contract call failed');
}
/**
* Returns the expected error message for the given revert reason resulting from
* a sendTransaction call. The exact error message depends on the backing
* Ethereum node and whether it supports revert reasons.
* @param reason a specific revert reason.
* @returns the expected error message.
*/
export async function getRevertReasonOrErrorMessageForSendTransactionAsync(reason: RevertReason): Promise<string> {
return _getGanacheOrGethError(reason, 'always failing transaction');
}
/**
* Rejects if the given Promise does not reject with an error indicating
* insufficient funds.

View File

@@ -0,0 +1,113 @@
import { BigNumber } from '@0xproject/utils';
import * as combinatorics from 'js-combinatorics';
import { testWithReferenceFuncAsync } from './test_with_reference';
// A set of values corresponding to the uint256 type in Solidity. This set
// contains some notable edge cases, including some values which will overflow
// the uint256 type when used in different mathematical operations.
export const uint256Values = [
new BigNumber(0),
new BigNumber(1),
new BigNumber(2),
// Non-trivial big number.
new BigNumber(2).pow(64),
// Max that does not overflow when squared.
new BigNumber(2).pow(128).minus(1),
// Min that does overflow when squared.
new BigNumber(2).pow(128),
// Max that does not overflow when doubled.
new BigNumber(2).pow(255).minus(1),
// Min that does overflow when doubled.
new BigNumber(2).pow(255),
// Max that does not overflow.
new BigNumber(2).pow(256).minus(1),
];
// A set of values corresponding to the bytes32 type in Solidity.
export const bytes32Values = [
// Min
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000000000000000000000000000002',
// Non-trivial big number.
'0x000000000000f000000000000000000000000000000000000000000000000000',
// Max
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
];
export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, R>(
name: string,
referenceFunc: (p0: P0, p1: P1) => Promise<R>,
testFunc: (p0: P0, p1: P1) => Promise<R>,
allValues: [P0[], P1[]],
): Promise<void>;
export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, R>(
name: string,
referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
allValues: [P0[], P1[], P2[]],
): Promise<void>;
export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, R>(
name: string,
referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
allValues: [P0[], P1[], P2[], P3[]],
): Promise<void>;
export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>(
name: string,
referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
allValues: [P0[], P1[], P2[], P3[], P4[]],
): Promise<void>;
/**
* Uses combinatorics to test the behavior of a test function by comparing it to
* the expected behavior (defined by a reference function) for a large number of
* possible input values.
*
* First generates test cases by taking the cartesian product of the given
* values. Each test case is a set of N values corresponding to the N arguments
* for the test func and the reference func. For each test case, first the
* reference function will be called to obtain an "expected result", or if the
* reference function throws/rejects, an "expected error". Next, the test
* function will be called to obtain an "actual result", or if the test function
* throws/rejects, an "actual error". Each test case passes if at least one of
* the following conditions is met:
*
* 1) Neither the reference function or the test function throw and the
* "expected result" equals the "actual result".
*
* 2) Both the reference function and the test function throw and the "actual
* error" message *contains* the "expected error" message.
*
* The first test case which does not meet one of these conditions will cause
* the entire test to fail and this function will throw/reject.
*
* @param referenceFuncAsync a reference function implemented in pure
* JavaScript/TypeScript which accepts N arguments and returns the "expected
* result" or "expected error" for a given test case.
* @param testFuncAsync a test function which, e.g., makes a call or sends a
* transaction to a contract. It accepts the same N arguments returns the
* "actual result" or "actual error" for a given test case.
* @param values an array of N arrays. Each inner array is a set of possible
* values which are passed into both the reference function and the test
* function.
* @return A Promise that resolves if the test passes and rejects if the test
* fails, according to the rules described above.
*/
export async function testCombinatoriallyWithReferenceFuncAsync(
name: string,
referenceFuncAsync: (...args: any[]) => Promise<any>,
testFuncAsync: (...args: any[]) => Promise<any>,
allValues: any[],
): Promise<void> {
const testCases = combinatorics.cartesianProduct(...allValues);
let counter = 0;
testCases.forEach(async testCase => {
counter += 1;
it(`${name} ${counter}/${testCases.length}`, async () => {
await testWithReferenceFuncAsync(referenceFuncAsync, testFuncAsync, testCase as any);
});
});
}

View File

@@ -8,7 +8,7 @@ import { ExchangeContract } from '../../generated_contract_wrappers/exchange';
import { formatters } from './formatters';
import { LogDecoder } from './log_decoder';
import { orderUtils } from './order_utils';
import { OrderInfo, SignedTransaction } from './types';
import { FillResults, OrderInfo, SignedTransaction } from './types';
export class ExchangeWrapper {
private readonly _exchange: ExchangeContract;
@@ -243,4 +243,27 @@ export class ExchangeWrapper {
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
public async getFillOrderResultsAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber } = {},
): Promise<FillResults> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const fillResults = await this._exchange.fillOrder.callAsync(
params.order,
params.takerAssetFillAmount,
params.signature,
{ from },
);
return fillResults;
}
public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
return data;
}
}

View File

@@ -15,6 +15,7 @@ import * as _ from 'lodash';
import 'make-promises-safe';
import { ExchangeContract, ExchangeFillEventArgs } from '../../generated_contract_wrappers/exchange';
import { TestLibsContract } from '../../generated_contract_wrappers/test_libs';
import { artifacts } from './artifacts';
import { expectTransactionFailedAsync } from './assertions';
@@ -46,16 +47,16 @@ chaiSetup.configure();
const expect = chai.expect;
/**
* Instantiates a new instance of CoreCombinatorialUtils. Since this method has some
* Instantiates a new instance of FillOrderCombinatorialUtils. Since this method has some
* required async setup, a factory method is required.
* @param web3Wrapper Web3Wrapper instance
* @param txDefaults Default Ethereum tx options
* @return CoreCombinatorialUtils instance
* @return FillOrderCombinatorialUtils instance
*/
export async function coreCombinatorialUtilsFactoryAsync(
export async function fillOrderCombinatorialUtilsFactoryAsync(
web3Wrapper: Web3Wrapper,
txDefaults: Partial<TxData>,
): Promise<CoreCombinatorialUtils> {
): Promise<FillOrderCombinatorialUtils> {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
const userAddresses = _.slice(accounts, 0, 5);
const [ownerAddress, makerAddress, takerAddress] = userAddresses;
@@ -123,7 +124,9 @@ export async function coreCombinatorialUtilsFactoryAsync(
exchangeContract.address,
);
const coreCombinatorialUtils = new CoreCombinatorialUtils(
const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults);
const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils(
orderFactory,
ownerAddress,
makerAddress,
@@ -132,11 +135,12 @@ export async function coreCombinatorialUtilsFactoryAsync(
zrxAssetData,
exchangeWrapper,
assetWrapper,
testLibsContract,
);
return coreCombinatorialUtils;
return fillOrderCombinatorialUtils;
}
export class CoreCombinatorialUtils {
export class FillOrderCombinatorialUtils {
public orderFactory: OrderFactoryFromScenario;
public ownerAddress: string;
public makerAddress: string;
@@ -145,6 +149,7 @@ export class CoreCombinatorialUtils {
public zrxAssetData: string;
public exchangeWrapper: ExchangeWrapper;
public assetWrapper: AssetWrapper;
public testLibsContract: TestLibsContract;
public static generateFillOrderCombinations(): FillScenario[] {
const takerScenarios = [
TakerScenario.Unspecified,
@@ -240,7 +245,7 @@ export class CoreCombinatorialUtils {
// AllowanceAmountScenario.TooLow,
// AllowanceAmountScenario.Unlimited,
];
const fillScenarioArrays = CoreCombinatorialUtils._getAllCombinations([
const fillScenarioArrays = FillOrderCombinatorialUtils._getAllCombinations([
takerScenarios,
feeRecipientScenarios,
makerAssetAmountScenario,
@@ -309,7 +314,7 @@ export class CoreCombinatorialUtils {
} else {
const result = [];
const restOfArrays = arrays.slice(1);
const allCombinationsOfRemaining = CoreCombinatorialUtils._getAllCombinations(restOfArrays); // recur with the rest of array
const allCombinationsOfRemaining = FillOrderCombinatorialUtils._getAllCombinations(restOfArrays); // recur with the rest of array
// tslint:disable:prefer-for-of
for (let i = 0; i < allCombinationsOfRemaining.length; i++) {
for (let j = 0; j < arrays[0].length; j++) {
@@ -329,6 +334,7 @@ export class CoreCombinatorialUtils {
zrxAssetData: string,
exchangeWrapper: ExchangeWrapper,
assetWrapper: AssetWrapper,
testLibsContract: TestLibsContract,
) {
this.orderFactory = orderFactory;
this.ownerAddress = ownerAddress;
@@ -338,6 +344,7 @@ export class CoreCombinatorialUtils {
this.zrxAssetData = zrxAssetData;
this.exchangeWrapper = exchangeWrapper;
this.assetWrapper = assetWrapper;
this.testLibsContract = testLibsContract;
}
public async testFillOrderScenarioAsync(
provider: Provider,
@@ -410,6 +417,8 @@ export class CoreCombinatorialUtils {
lazyStore,
fillRevertReasonIfExists,
);
await this._abiEncodeFillOrderAndAssertOutcomeAsync(signedOrder, takerAssetFillAmount);
}
private async _fillOrderAndAssertOutcomeAsync(
signedOrder: SignedOrder,
@@ -456,6 +465,29 @@ export class CoreCombinatorialUtils {
signedOrder.takerAssetAmount,
signedOrder.makerAssetAmount,
);
const expMakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.makerFee,
);
const expTakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.takerFee,
);
const fillResults = await this.exchangeWrapper.getFillOrderResultsAsync(signedOrder, this.takerAddress, {
takerAssetFillAmount,
});
expect(fillResults.takerAssetFilledAmount).to.be.bignumber.equal(
expFilledTakerAmount,
'takerAssetFilledAmount',
);
expect(fillResults.makerAssetFilledAmount).to.be.bignumber.equal(
expFilledMakerAmount,
'makerAssetFilledAmount',
);
expect(fillResults.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'takerFeePaid');
expect(fillResults.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'makerFeePaid');
// - Let's fill the order!
const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, {
@@ -479,17 +511,7 @@ export class CoreCombinatorialUtils {
expFilledTakerAmount,
'log.args.takerAssetFilledAmount',
);
const expMakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.makerFee,
);
expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid');
const expTakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.takerFee,
);
expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid');
expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash');
expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData');
@@ -571,6 +593,19 @@ export class CoreCombinatorialUtils {
'ZRXAssetBalanceOfFeeRecipient',
);
}
private async _abiEncodeFillOrderAndAssertOutcomeAsync(
signedOrder: SignedOrder,
takerAssetFillAmount: BigNumber,
): Promise<void> {
const params = orderUtils.createFill(signedOrder, takerAssetFillAmount);
const expectedAbiEncodedData = this.exchangeWrapper.abiEncodeFillOrder(signedOrder, { takerAssetFillAmount });
const libsAbiEncodedData = await this.testLibsContract.publicAbiEncodeFillOrder.callAsync(
params.order,
params.takerAssetFillAmount,
params.signature,
);
expect(libsAbiEncodedData).to.be.equal(expectedAbiEncodedData, 'ABIEncodedFillOrderData');
}
private async _getTakerAssetFillAmountAsync(
signedOrder: SignedOrder,
takerAssetFillAmountScenario: TakerAssetFillAmountScenario,

View File

@@ -106,12 +106,12 @@ export class ForwarderWrapper {
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
public async withdrawERC20Async(
tokenAddress: string,
public async withdrawAssetAsync(
assetData: string,
amount: BigNumber,
txData: TxDataPayable,
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._forwarderContract.withdrawERC20.sendTransactionAsync(tokenAddress, amount, txData);
const txHash = await this._forwarderContract.withdrawAsset.sendTransactionAsync(assetData, amount, txData);
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}

View File

@@ -0,0 +1,119 @@
import * as chai from 'chai';
import * as _ from 'lodash';
import { chaiSetup } from './chai_setup';
chaiSetup.configure();
const expect = chai.expect;
export async function testWithReferenceFuncAsync<P0, R>(
referenceFunc: (p0: P0) => Promise<R>,
testFunc: (p0: P0) => Promise<R>,
values: [P0],
): Promise<void>;
export async function testWithReferenceFuncAsync<P0, P1, R>(
referenceFunc: (p0: P0, p1: P1) => Promise<R>,
testFunc: (p0: P0, p1: P1) => Promise<R>,
values: [P0, P1],
): Promise<void>;
export async function testWithReferenceFuncAsync<P0, P1, P2, R>(
referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
values: [P0, P1, P2],
): Promise<void>;
export async function testWithReferenceFuncAsync<P0, P1, P2, P3, R>(
referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
values: [P0, P1, P2, P3],
): Promise<void>;
export async function testWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>(
referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
values: [P0, P1, P2, P3, P4],
): Promise<void>;
/**
* Tests the behavior of a test function by comparing it to the expected
* behavior (defined by a reference function).
*
* First the reference function will be called to obtain an "expected result",
* or if the reference function throws/rejects, an "expected error". Next, the
* test function will be called to obtain an "actual result", or if the test
* function throws/rejects, an "actual error". The test passes if at least one
* of the following conditions is met:
*
* 1) Neither the reference function or the test function throw and the
* "expected result" equals the "actual result".
*
* 2) Both the reference function and the test function throw and the "actual
* error" message *contains* the "expected error" message.
*
* @param referenceFuncAsync a reference function implemented in pure
* JavaScript/TypeScript which accepts N arguments and returns the "expected
* result" or throws/rejects with the "expected error".
* @param testFuncAsync a test function which, e.g., makes a call or sends a
* transaction to a contract. It accepts the same N arguments returns the
* "actual result" or throws/rejects with the "actual error".
* @param values an array of N values, where each value corresponds in-order to
* an argument to both the test function and the reference function.
* @return A Promise that resolves if the test passes and rejects if the test
* fails, according to the rules described above.
*/
export async function testWithReferenceFuncAsync(
referenceFuncAsync: (...args: any[]) => Promise<any>,
testFuncAsync: (...args: any[]) => Promise<any>,
values: any[],
): Promise<void> {
let expectedResult: any;
let expectedErr: string | undefined;
try {
expectedResult = await referenceFuncAsync(...values);
} catch (e) {
expectedErr = e.message;
}
let actualResult: any | undefined;
try {
actualResult = await testFuncAsync(...values);
if (!_.isUndefined(expectedErr)) {
throw new Error(
`Expected error containing ${expectedErr} but got no error\n\tTest case: ${_getTestCaseString(
referenceFuncAsync,
values,
)}`,
);
}
} catch (e) {
if (_.isUndefined(expectedErr)) {
throw new Error(`${e.message}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`);
} else {
expect(e.message).to.contain(
expectedErr,
`${e.message}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`,
);
}
}
if (!_.isUndefined(actualResult) && !_.isUndefined(expectedResult)) {
expect(actualResult).to.deep.equal(
expectedResult,
`Test case: ${_getTestCaseString(referenceFuncAsync, values)}`,
);
}
}
function _getTestCaseString(referenceFuncAsync: (...args: any[]) => Promise<any>, values: any[]): string {
const paramNames = _getParameterNames(referenceFuncAsync);
return JSON.stringify(_.zipObject(paramNames, values));
}
// Source: https://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically
function _getParameterNames(func: (...args: any[]) => any): string[] {
return _.toString(func)
.replace(/[/][/].*$/gm, '') // strip single-line comments
.replace(/\s+/g, '') // strip white space
.replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments
.split('){', 1)[0]
.replace(/^[^(]*[(]/, '') // extract the parameters
.replace(/=[^,]+/g, '') // strip any ES6 defaults
.split(',')
.filter(Boolean); // split & filter [""]
}

View File

@@ -1,13 +1,22 @@
[
{
"timestamp": 1532614997,
"version": "1.0.3",
"timestamp": 1534210131,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1532619515
},
{
"timestamp": 1532605697,
"version": "1.0.2",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.4 - _August 13, 2018_
* Dependencies updated
## v1.0.3 - _July 26, 2018_
* Dependencies updated
@@ -17,7 +21,7 @@ CHANGELOG
* Dependencies updated
## v1.0.0 - _July 20, 2018_
## v1.0.0 - _July 19, 2018_
* Dependencies updated
@@ -43,7 +47,7 @@ CHANGELOG
* Pass SolCompilerArtifactAdapter to CoverageSubprovider (#589)
* Move callbackErrorReporter over from 0x.js (#579)
## v0.4.1 - _May 5, 2018_
## v0.4.1 - _May 4, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/dev-utils",
"version": "1.0.2",
"version": "1.0.3",
"engines": {
"node": ">=6.12"
},
@@ -30,28 +30,28 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/dev-utils/README.md",
"devDependencies": {
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"chai": "^4.0.1",
"copyfiles": "^1.2.0",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"dependencies": {
"@0xproject/subproviders": "^1.0.2",
"@0xproject/types": "^1.0.1-rc.1",
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"@0xproject/web3-wrapper": "^1.1.0",
"ethereum-types": "^1.0.2",
"lodash": "^4.17.4"
"@0xproject/subproviders": "^1.0.4",
"@0xproject/types": "^1.0.1-rc.3",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"@0xproject/web3-wrapper": "^1.1.2",
"ethereum-types": "^1.0.3",
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1534210131,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1532614997,
"version": "1.0.3",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.4 - _August 13, 2018_
* Dependencies updated
## v1.0.3 - _July 26, 2018_
* Dependencies updated
@@ -17,11 +21,11 @@ CHANGELOG
* Dependencies updated
## v1.0.0 - _July 20, 2018_
## v1.0.0 - _July 19, 2018_
* Add `TraceParams` interface for `debug_traceTransaction` parameters (#675)
* Add `TransactionReceiptStatus` type (#812)
## v0.0.2 - _June 1, 2018_
## v0.0.2 - _May 31, 2018_
* Initial publish (#642)

View File

@@ -1,6 +1,6 @@
{
"name": "ethereum-types",
"version": "1.0.2",
"version": "1.0.3",
"engines": {
"node": ">=6.12"
},
@@ -35,13 +35,13 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/ethereum-types/README.md",
"devDependencies": {
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"copyfiles": "^1.2.0",
"make-promises-safe": "^1.1.0",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"dependencies": {
"@types/node": "^8.0.53",

View File

@@ -1,4 +1,18 @@
[
{
"version": "1.0.1-rc.3",
"changes": [
{
"note":
"Updated to use latest orderFactory interface, fixed `feeRecipient` spelling error in public interface",
"pr": 936
},
{
"note": "Dependencies updated"
}
],
"timestamp": 1534210131
},
{
"version": "1.0.1-rc.2",
"changes": [
@@ -6,7 +20,7 @@
"note": "Dependencies updated"
}
],
"timestamp": 1532614997
"timestamp": 1532619515
},
{
"version": "1.0.1-rc.1",

View File

@@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.1-rc.3 - _August 13, 2018_
* Updated to use latest orderFactory interface, fixed `feeRecipient` spelling error in public interface (#936)
* Dependencies updated
## v1.0.1-rc.2 - _July 26, 2018_
* Dependencies updated
@@ -17,7 +22,7 @@ CHANGELOG
* Dependencies updated
## v1.0.0-rc.1 - _July 20, 2018_
## v1.0.0-rc.1 - _July 19, 2018_
* Make fill-scenarios compatible with V2 of 0x protocol (#656)

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/fill-scenarios",
"version": "1.0.1-rc.1",
"version": "1.0.1-rc.2",
"description": "0x order fill scenario generator",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@@ -28,28 +28,28 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md",
"devDependencies": {
"@0xproject/abi-gen": "^1.0.2",
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/sol-compiler": "^1.0.2",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/abi-gen": "^1.0.4",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/sol-compiler": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@types/lodash": "4.14.104",
"copyfiles": "^1.2.0",
"make-promises-safe": "^1.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"dependencies": {
"@0xproject/base-contract": "^1.0.2",
"@0xproject/order-utils": "^1.0.1-rc.1",
"@0xproject/types": "^1.0.1-rc.1",
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/utils": "^1.0.2",
"@0xproject/web3-wrapper": "^1.1.0",
"ethereum-types": "^1.0.2",
"@0xproject/base-contract": "^1.0.4",
"@0xproject/order-utils": "^1.0.1-rc.2",
"@0xproject/types": "^1.0.1-rc.3",
"@0xproject/typescript-typings": "^1.0.3",
"@0xproject/utils": "^1.0.4",
"@0xproject/web3-wrapper": "^1.1.2",
"ethereum-types": "^1.0.3",
"ethers": "3.0.22",
"lodash": "^4.17.4"
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"

View File

@@ -61,7 +61,7 @@ export class FillScenarios {
makerAddress: string,
takerAddress: string,
fillableAmount: BigNumber,
feeRecepientAddress: string,
feeRecipientAddress: string,
expirationTimeSeconds?: BigNumber,
): Promise<SignedOrder> {
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
@@ -73,7 +73,7 @@ export class FillScenarios {
takerAddress,
fillableAmount,
fillableAmount,
feeRecepientAddress,
feeRecipientAddress,
expirationTimeSeconds,
);
}
@@ -88,7 +88,7 @@ export class FillScenarios {
): Promise<SignedOrder> {
const makerFee = new BigNumber(0);
const takerFee = new BigNumber(0);
const feeRecepientAddress = constants.NULL_ADDRESS;
const feeRecipientAddress = constants.NULL_ADDRESS;
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
makerAssetData,
takerAssetData,
@@ -98,7 +98,7 @@ export class FillScenarios {
takerAddress,
makerFillableAmount,
takerFillableAmount,
feeRecepientAddress,
feeRecipientAddress,
expirationTimeSeconds,
);
}
@@ -148,7 +148,7 @@ export class FillScenarios {
takerAddress: string,
makerFillableAmount: BigNumber,
takerFillableAmount: BigNumber,
feeRecepientAddress: string,
feeRecipientAddress: string,
expirationTimeSeconds?: BigNumber,
): Promise<SignedOrder> {
const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(makerAssetData);
@@ -194,17 +194,19 @@ export class FillScenarios {
const signedOrder = await orderFactory.createSignedOrderAsync(
this._web3Wrapper.getProvider(),
makerAddress,
takerAddress,
senderAddress,
makerFee,
takerFee,
makerFillableAmount,
makerAssetData,
takerFillableAmount,
takerAssetData,
this._exchangeAddress,
feeRecepientAddress,
expirationTimeSeconds,
{
takerAddress,
senderAddress,
makerFee,
takerFee,
feeRecipientAddress,
expirationTimeSeconds,
},
);
return signedOrder;
}

View File

@@ -1,4 +1,31 @@
[
{
"version": "1.0.1-rc.4",
"changes": [
{
"note": "Allow for additional properties in txData schema",
"pr": 938
},
{
"note": "Change hexSchema to match `0x`",
"pr": 937
},
{
"note": "Upgrade Relayer API schemas for relayer API V2",
"pr": 916
}
],
"timestamp": 1534210131
},
{
"version": "1.0.1-rc.3",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1532619515
},
{
"version": "1.0.1-rc.2",
"changes": [

View File

@@ -5,6 +5,16 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.1-rc.4 - _August 13, 2018_
* Allow for additional properties in txData schema (#938)
* Change hexSchema to match `0x` (#937)
* Upgrade Relayer API schemas for relayer API V2 (#916)
## v1.0.1-rc.3 - _July 26, 2018_
* Dependencies updated
## v1.0.1-rc.2 - _July 26, 2018_
* Dependencies updated
@@ -17,7 +27,7 @@ CHANGELOG
* Dependencies updated
## v1.0.0-rc.1 - _July 20, 2018_
## v1.0.0-rc.1 - _July 19, 2018_
* Update schemas for V2 or 0x Protocol (#615)
* Added CallData schema (#821)
@@ -43,7 +53,7 @@ CHANGELOG
* Dependencies updated
## v0.7.23 - _May 5, 2018_
## v0.7.23 - _May 4, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/json-schemas",
"version": "1.0.1-rc.1",
"version": "1.0.1-rc.3",
"engines": {
"node": ">=6.12"
},
@@ -47,15 +47,15 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/json-schemas/README.md",
"dependencies": {
"@0xproject/typescript-typings": "^1.0.2",
"@0xproject/typescript-typings": "^1.0.3",
"@types/node": "^8.0.53",
"jsonschema": "^1.2.0",
"lodash.values": "^4.3.0"
},
"devDependencies": {
"@0xproject/monorepo-scripts": "^1.0.3",
"@0xproject/tslint-config": "^1.0.3",
"@0xproject/utils": "^1.0.2",
"@0xproject/monorepo-scripts": "^1.0.4",
"@0xproject/tslint-config": "^1.0.4",
"@0xproject/utils": "^1.0.4",
"@types/lodash.foreach": "^4.5.3",
"@types/lodash.values": "^4.3.3",
"@types/mocha": "^2.2.42",
@@ -64,13 +64,13 @@
"dirty-chai": "^2.0.1",
"lodash.foreach": "^4.5.0",
"make-promises-safe": "^1.1.0",
"mocha": "^4.0.1",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"shx": "^0.2.2",
"tslint": "5.11.0",
"typedoc": "0xProject/typedoc",
"typescript": "2.7.1"
"typescript": "2.9.2"
},
"publishConfig": {
"access": "public"

View File

@@ -1,17 +1,17 @@
export const addressSchema = {
id: '/Address',
id: '/addressSchema',
type: 'string',
pattern: '^0x[0-9a-f]{40}$',
};
export const hexSchema = {
id: '/Hex',
id: '/hexSchema',
type: 'string',
pattern: '^0x([0-9a-f][0-9a-f])+$',
pattern: '^0x(([0-9a-f][0-9a-f])+)?$',
};
export const numberSchema = {
id: '/Number',
id: '/numberSchema',
type: 'string',
pattern: '^\\d+(\\.\\d+)?$',
};

View File

@@ -1,5 +1,5 @@
export const blockParamSchema = {
id: '/BlockParam',
id: '/blockParamSchema',
oneOf: [
{
type: 'number',
@@ -11,10 +11,10 @@ export const blockParamSchema = {
};
export const blockRangeSchema = {
id: '/BlockRange',
id: '/blockRangeSchema',
properties: {
fromBlock: { $ref: '/BlockParam' },
toBlock: { $ref: '/BlockParam' },
fromBlock: { $ref: '/blockParamSchema' },
toBlock: { $ref: '/blockParamSchema' },
},
type: 'object',
};

View File

@@ -1,16 +1,16 @@
export const callDataSchema = {
id: '/CallData',
id: '/callDataSchema',
properties: {
from: { $ref: '/Address' },
to: { $ref: '/Address' },
from: { $ref: '/addressSchema' },
to: { $ref: '/addressSchema' },
value: {
oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
oneOf: [{ $ref: '/numberSchema' }, { $ref: '/jsNumber' }],
},
gas: {
oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
oneOf: [{ $ref: '/numberSchema' }, { $ref: '/jsNumber' }],
},
gasPrice: {
oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
oneOf: [{ $ref: '/numberSchema' }, { $ref: '/jsNumber' }],
},
data: {
type: 'string',

View File

@@ -1,5 +1,5 @@
export const ecSignatureParameterSchema = {
id: '/ECSignatureParameter',
id: '/ecSignatureParameterSchema',
type: 'string',
pattern: '^0[xX][0-9A-Fa-f]{64}$',
};
@@ -12,8 +12,8 @@ export const ecSignatureSchema = {
minimum: 27,
maximum: 28,
},
r: { $ref: '/ECSignatureParameter' },
s: { $ref: '/ECSignatureParameter' },
r: { $ref: '/ecSignatureParameterSchema' },
s: { $ref: '/ecSignatureParameterSchema' },
},
required: ['v', 'r', 's'],
type: 'object',

View File

@@ -1,7 +1,7 @@
export const indexFilterValuesSchema = {
id: '/IndexFilterValues',
id: '/indexFilterValuesSchema',
additionalProperties: {
oneOf: [{ $ref: '/Number' }, { $ref: '/Address' }, { $ref: '/OrderHashSchema' }],
oneOf: [{ $ref: '/numberSchema' }, { $ref: '/addressSchema' }, { $ref: '/orderHashSchema' }],
},
type: 'object',
};

View File

@@ -1,10 +1,10 @@
export const orderCancellationRequestsSchema = {
id: '/OrderCancellationRequests',
id: '/orderCancellationRequestsSchema',
type: 'array',
items: {
properties: {
order: { $ref: '/Order' },
takerTokenCancelAmount: { $ref: '/Number' },
order: { $ref: '/orderSchema' },
takerTokenCancelAmount: { $ref: '/numberSchema' },
},
required: ['order', 'takerTokenCancelAmount'],
type: 'object',

View File

@@ -1,10 +1,10 @@
export const orderFillOrKillRequestsSchema = {
id: '/OrderFillOrKillRequests',
id: '/orderFillOrKillRequestsSchema',
type: 'array',
items: {
properties: {
signedOrder: { $ref: '/SignedOrder' },
fillTakerAmount: { $ref: '/Number' },
signedOrder: { $ref: '/signedOrderSchema' },
fillTakerAmount: { $ref: '/numberSchema' },
},
required: ['signedOrder', 'fillTakerAmount'],
type: 'object',

View File

@@ -1,10 +1,10 @@
export const orderFillRequestsSchema = {
id: '/OrderFillRequests',
id: '/orderFillRequestsSchema',
type: 'array',
items: {
properties: {
signedOrder: { $ref: '/SignedOrder' },
takerTokenFillAmount: { $ref: '/Number' },
signedOrder: { $ref: '/signedOrderSchema' },
takerTokenFillAmount: { $ref: '/numberSchema' },
},
required: ['signedOrder', 'takerTokenFillAmount'],
type: 'object',

View File

@@ -1,5 +1,5 @@
export const orderHashSchema = {
id: '/OrderHashSchema',
id: '/orderHashSchema',
type: 'string',
pattern: '^0x[0-9a-fA-F]{64}$',
};

View File

@@ -1,19 +1,19 @@
export const orderSchema = {
id: '/Order',
id: '/orderSchema',
properties: {
makerAddress: { $ref: '/Address' },
takerAddress: { $ref: '/Address' },
makerFee: { $ref: '/Number' },
takerFee: { $ref: '/Number' },
senderAddress: { $ref: '/Address' },
makerAssetAmount: { $ref: '/Number' },
takerAssetAmount: { $ref: '/Number' },
makerAssetData: { $ref: '/Hex' },
takerAssetData: { $ref: '/Hex' },
salt: { $ref: '/Number' },
exchangeAddress: { $ref: '/Address' },
feeRecipientAddress: { $ref: '/Address' },
expirationTimeSeconds: { $ref: '/Number' },
makerAddress: { $ref: '/addressSchema' },
takerAddress: { $ref: '/addressSchema' },
makerFee: { $ref: '/numberSchema' },
takerFee: { $ref: '/numberSchema' },
senderAddress: { $ref: '/addressSchema' },
makerAssetAmount: { $ref: '/numberSchema' },
takerAssetAmount: { $ref: '/numberSchema' },
makerAssetData: { $ref: '/hexSchema' },
takerAssetData: { $ref: '/hexSchema' },
salt: { $ref: '/numberSchema' },
exchangeAddress: { $ref: '/addressSchema' },
feeRecipientAddress: { $ref: '/addressSchema' },
expirationTimeSeconds: { $ref: '/numberSchema' },
},
required: [
'makerAddress',
@@ -34,12 +34,12 @@ export const orderSchema = {
};
export const signedOrderSchema = {
id: '/SignedOrder',
id: '/signedOrderSchema',
allOf: [
{ $ref: '/Order' },
{ $ref: '/orderSchema' },
{
properties: {
signature: { $ref: '/Hex' },
signature: { $ref: '/hexSchema' },
},
required: ['signature'],
},

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