Compare commits

..

86 Commits

Author SHA1 Message Date
Fabio Berger
1b35a6e3b5 Publish
- 0x.js@1.0.6
 - @0xproject/abi-gen@1.0.11
 - @0xproject/assert@1.0.11
 - @0xproject/asset-buyer@1.0.1
 - @0xproject/base-contract@2.0.5
 - @0xproject/connect@2.0.4
 - @0xproject/contract-wrappers@2.0.0
 - contracts@2.1.47
 - @0xproject/dev-utils@1.0.10
 - ethereum-types@1.0.8
 - @0xproject/fill-scenarios@1.0.5
 - @0xproject/json-schemas@1.0.4
 - @0xproject/metacoin@0.0.21
 - @0xproject/migrations@1.0.12
 - @0xproject/order-utils@1.0.5
 - @0xproject/order-watcher@2.0.0
 - @0xproject/react-docs@1.0.11
 - @0xproject/react-shared@1.0.12
 - @0xproject/sol-compiler@1.1.5
 - @0xproject/sol-cov@2.1.5
 - @0xproject/sol-resolver@1.0.11
 - @0xproject/sra-report@1.0.11
 - @0xproject/sra-spec@1.0.4
 - @0xproject/subproviders@2.0.5
 - @0xproject/testnet-faucets@1.0.49
 - @0xproject/types@1.1.1
 - @0xproject/typescript-typings@2.0.2
 - @0xproject/utils@1.0.11
 - @0xproject/web3-wrapper@3.0.1
 - @0xproject/website@0.0.52
2018-09-25 21:34:14 +01:00
Fabio Berger
900a8aee76 Updated CHANGELOGS 2018-09-25 21:33:55 +01:00
Fabio Berger
adf5acd5c4 Update yarn.lock 2018-09-25 21:23:06 +01:00
Fabio Berger
b40861747b Properly render function generic types that don't extend another type 2018-09-25 17:34:22 +01:00
Fabio Berger
b73df28454 Merge pull request #1087 from 0xProject/addTxHashToOrderState
Add transactionHash to OrderState and emit it from OrderWatcher
2018-09-25 16:37:24 +01:00
Fabio Berger
5afc739397 Add changelog entry 2018-09-25 16:37:08 +01:00
Fabio Berger
9eecf3683b Add transactionHash to OrderState and emit it from OrderWatcher subscription 2018-09-25 16:10:13 +01:00
Fabio Berger
7570f3db51 Merge pull request #1080 from 0xProject/upgradeBlockstream
Fix dropped events issue in Order-watcher and Contract-wrappers subscriptions
2018-09-25 14:59:37 +01:00
Fabio Berger
977d55c61b merge development 2018-09-25 13:07:14 +01:00
Leonid Logvinov
78ef98c27c Publish
- 0x.js@1.0.5
 - @0xproject/abi-gen@1.0.10
 - @0xproject/assert@1.0.10
 - @0xproject/asset-buyer@1.0.0
 - @0xproject/base-contract@2.0.4
 - @0xproject/connect@2.0.3
 - @0xproject/contract-wrappers@1.0.5
 - contracts@2.1.46
 - @0xproject/dev-utils@1.0.9
 - @0xproject/fill-scenarios@1.0.4
 - @0xproject/json-schemas@1.0.3
 - @0xproject/metacoin@0.0.20
 - @0xproject/migrations@1.0.11
 - @0xproject/order-utils@1.0.4
 - @0xproject/order-watcher@1.0.5
 - @0xproject/react-docs@1.0.10
 - @0xproject/react-shared@1.0.11
 - @0xproject/sol-compiler@1.1.4
 - @0xproject/sol-cov@2.1.4
 - @0xproject/sol-resolver@1.0.10
 - @0xproject/sra-report@1.0.10
 - @0xproject/sra-spec@1.0.3
 - @0xproject/subproviders@2.0.4
 - @0xproject/testnet-faucets@1.0.48
 - @0xproject/types@1.1.0
 - @0xproject/utils@1.0.10
 - @0xproject/web3-wrapper@3.0.0
 - @0xproject/website@0.0.51
2018-09-25 13:48:55 +02:00
Leonid Logvinov
411813d8d9 Updated CHANGELOGS 2018-09-25 13:48:44 +02:00
Leonid Logvinov
64f41259eb Merge pull request #1085 from 0xProject/feature/export-sra-types
[sra-types] Move SRA types from @0xproject/connect to @0xproject/types
2018-09-25 13:36:47 +02:00
Fabio Berger
fc3acec669 Fix lint issues 2018-09-25 12:32:20 +01:00
Leonid Logvinov
b85db17e75 Move SRA types from @0xproject/connect to @0xproject/sra-types 2018-09-25 13:12:12 +02:00
Fabio Berger
a05530f821 Fix prettier 2018-09-25 12:06:37 +01:00
Fabio Berger
173b36c54c Fix prettier 2018-09-25 12:06:28 +01:00
Fabio Berger
55ca971186 Decode logs received from blockstream 2018-09-25 12:05:44 +01:00
Fabio Berger
284930eb58 Add missing type 2018-09-25 11:30:27 +01:00
Fabio Berger
902691e289 Update changelogs 2018-09-25 11:29:36 +01:00
Fabio Berger
0afe55f2ff Refactor blockstream integration to use the proper callback method interface 2018-09-25 11:20:09 +01:00
Fabio Berger
21910a7129 Add entry about newly exposed method 2018-09-25 11:02:49 +01:00
Fabio Berger
9c89d1e99b Expose method to send raw JSON RPC payloads 2018-09-25 10:45:11 +01:00
Alex Browne
408f573188 Use the 0xorg DockerHub account instead of albrow (#1084) 2018-09-24 14:31:26 -07:00
Alex Browne
6f2ab23bd0 Feature/custom verdaccio dockerfile (#1083)
Create custom verdaccio docker image
2018-09-24 13:54:25 -07:00
Francesco Agosti
b830c28d83 Merge pull request #1037 from 0xProject/feature/forwarder-helper/sra-and-rpc
[asset-buyer] Create new AssetBuyer class
2018-09-24 17:47:59 +02:00
Francesco Agosti
4a316571ff Merge pull request #1073 from 0xProject/fix/website/signing-order-validation-bug
[website] Fix order creation and fill flow in Portal
2018-09-24 17:23:13 +02:00
Fabio Berger
5e1a2bd972 Merge development 2018-09-24 15:53:34 +01:00
Fabio Berger
fc33eacd2c Merge pull request #1082 from 0xProject/fixGetBlocks
Fix block fetch error if block not found
2018-09-24 15:49:58 +01:00
fragosti
748a8a8ae3 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into fix/website/signing-order-validation-bug 2018-09-24 16:48:47 +02:00
Fabio Berger
7516959c9f Add comments for clarity 2018-09-24 15:14:14 +01:00
Fabio Berger
311b925919 Add to doc comment why a block might not be returned to the caller 2018-09-24 15:14:07 +01:00
Fabio Berger
5d88a56452 Add PR nr 2018-09-24 15:11:29 +01:00
Fabio Berger
ebddf82819 Add CHANGELOG entry for change to getBlockAsync 2018-09-24 15:02:47 +01:00
Fabio Berger
d0448c2bbd Fix bug where if block wasn't found, getBlockAsync would throw. Now it returns undefined 2018-09-24 15:02:06 +01:00
fragosti
d8d1c98a40 Upgrade all deps 2018-09-24 15:53:34 +02:00
fragosti
f49b231e91 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/forwarder-helper/sra-and-rpc 2018-09-24 15:45:06 +02:00
fragosti
7a43e19116 Improve README 2018-09-24 15:43:02 +02:00
fragosti
e4b664bafa Add expiry buffer 2018-09-24 13:17:38 +02:00
Fabio Berger
8bce407aec Add order-utils to README list 2018-09-21 17:36:05 +01:00
fragosti
7a5376621f Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/forwarder-helper/sra-and-rpc 2018-09-21 17:20:48 +02:00
fragosti
5e84e9689f Small typos 2018-09-21 16:53:18 +02:00
fragosti
1bfaefb240 Add order provider response validation 2018-09-21 16:24:45 +02:00
fragosti
c48cf3ab3b Make asset buyer map private 2018-09-21 16:03:47 +02:00
fragosti
c64dcec772 More renaming 2018-09-21 15:58:04 +02:00
Fabio Berger
45dc2be083 Fix prettier 2018-09-21 14:53:25 +01:00
Fabio Berger
31f6fc065f Add changelog entries 2018-09-21 14:24:50 +01:00
fragosti
8dea48ebef Renamed orderFetcherResponseProcessor to orderProviderResponseProcessoer 2018-09-21 15:21:44 +02:00
fragosti
97150cf55f Add labels to TODOs 2018-09-21 14:56:54 +02:00
Fabio Berger
b0484eafe3 Upgrade blockstream to version that supports fetching logs by blockHash, fixing reliability issues 2018-09-21 13:46:10 +01:00
Fabio Berger
1b799e98e8 Add blockHash to FilterObject now that EIP234 is supported 2018-09-21 13:45:06 +01:00
Fabio Berger
e6840c60c7 Add assertion that one cannot specify both blockHash & fromBlock/toBlock to getLogsAsync 2018-09-21 13:43:06 +01:00
fragosti
fcca63a2dc Move some logic to order utils 2018-09-20 23:39:55 +02:00
fragosti
35c324f67c Add utility to get assetDatas 2018-09-20 19:00:23 +02:00
fragosti
03e18ff7c6 Rename OrderFetcher to OrderProvider and other small improvements 2018-09-20 15:10:15 +02:00
fragosti
d23487bda9 Update descriptions for methods on AssetBuyer 2018-09-20 14:27:20 +02:00
fragosti
3238925aa4 Add better description to README 2018-09-20 14:09:11 +02:00
fragosti
a44f77a838 Implement StandardRelayerAPIAssetBuyerManager 2018-09-19 18:38:50 +02:00
fragosti
a03b1d4d6c Move ObjectMap to shared types 2018-09-19 16:48:57 +02:00
fragosti
14345ab24e Rename forceOrderRefresh to shouldForceOrderRefresh 2018-09-19 16:02:52 +02:00
fragosti
60e2dfdbda Calculate min and max rates in buy quote 2018-09-19 15:58:30 +02:00
fragosti
93f7e33f6a Add isValidPercentage assert 2018-09-19 00:57:05 +02:00
fragosti
fd4b4f8f82 Make ForwaderWrapper take in a number for feePercentage instead of BigNumber 2018-09-18 23:56:07 +02:00
fragosti
0003666050 make the slippage percentage customizable by integrator 2018-09-18 16:42:52 +02:00
fragosti
b947609ff1 Restrict orders field of AssetBuyerOrdersAndFillableAmounts to SignedOrder for consistency 2018-09-18 16:26:50 +02:00
fragosti
38afd108f8 Fix order expired bug 2018-09-18 16:07:47 +02:00
fragosti
65f709d50a Move all constants to own file 2018-09-18 16:07:08 +02:00
fragosti
f5dbf212e3 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/forwarder-helper/sra-and-rpc 2018-09-18 15:58:47 +02:00
fragosti
f6e1bf78c8 Add yarn.lock 2018-09-18 14:33:47 +02:00
fragosti
950f279508 Merge branch 'development' of https://github.com/0xProject/0x-monorepo into fix/website/signing-order-validation-bug 2018-09-18 14:15:31 +02:00
fragosti
e46807c28b Fix order creation and fill flow in Portal 2018-09-18 13:55:31 +02:00
Brandon Millman
a22d2dc7ee Add factory method for specific assetData to buy and add comments 2018-09-15 15:05:27 +02:00
Brandon Millman
9ec2b5a2d5 Add factory method on AssetBuyer for specific token address 2018-09-15 14:53:04 +02:00
Brandon Millman
af40989f5f Add factory method on AssetBuyer for provided orders 2018-09-15 14:47:44 +02:00
Brandon Millman
d57619b5db Export the order fetchers 2018-09-15 14:16:08 +02:00
Brandon Millman
c692115cdc Fix lint errors 2018-09-15 14:14:55 +02:00
Brandon Millman
dfe58e4975 Delete old test 2018-09-15 14:14:55 +02:00
Brandon Millman
4e59be9afc Implement ProvidedOrderFetcher 2018-09-15 14:14:55 +02:00
Brandon Millman
190bf2599c Implement StandardRelayerAPIOrderFetcher 2018-09-15 14:14:55 +02:00
Brandon Millman
f1a22e9bd7 Flesh out the AssetBuyer class 2018-09-15 14:14:48 +02:00
Brandon Millman
7b46cef83d Create initial AssetBuyer class 2018-09-15 14:14:48 +02:00
Brandon Millman
8da7d39998 Update readme, changelog, and package.json with rename 2018-09-15 14:14:48 +02:00
Brandon Millman
91702bbae2 Move packages/forwarder-helper into packages/asset-buyer 2018-09-15 14:14:48 +02:00
Brandon Millman
90674d9038 Various clean up 2018-09-15 14:14:48 +02:00
Brandon Millman
c0a14a4a41 Catch standard relayer api errors 2018-09-15 14:14:48 +02:00
Brandon Millman
8d6132736b Remove taker address as param and filter out non-open orders 2018-09-15 14:14:48 +02:00
Brandon Millman
8687b9533c Add getForwarderHelperForMakerAssetDataAsync method to forwarderHelperFactory 2018-09-15 14:14:48 +02:00
157 changed files with 2725 additions and 1086 deletions

View File

@@ -51,7 +51,7 @@ jobs:
test-contracts-geth:
docker:
- image: circleci/node:9
- image: albrow/0x-devnet
- image: 0xorg/devnet
working_directory: ~/repo
steps:
- restore_cache:
@@ -64,7 +64,7 @@ jobs:
resource_class: medium+
docker:
- image: circleci/node:9
- image: verdaccio/verdaccio
- image: 0xorg/verdaccio
working_directory: ~/repo
steps:
- restore_cache:

View File

@@ -27,15 +27,16 @@ If you're developing on 0x now or are interested in using 0x infrastructure in t
| [`@0xproject/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0xproject/assert.svg)](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
| [`@0xproject/base-contract`](/packages/base-contract) | [![npm](https://img.shields.io/npm/v/@0xproject/base-contract.svg)](https://www.npmjs.com/package/@0xproject/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
| [`@0xproject/connect`](/packages/connect) | [![npm](https://img.shields.io/npm/v/@0xproject/connect.svg)](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the Standard Relayer API |
| [`@0xproject/sol-compiler`](/packages/sol-compiler) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-compiler.svg)](https://www.npmjs.com/package/@0xproject/sol-compiler) | A thin wrapper around Solc.js that outputs artifacts, resolves imports, only re-compiles when needed, and other niceties. |
| [`@0xproject/dev-utils`](/packages/dev-utils) | [![npm](https://img.shields.io/npm/v/@0xproject/dev-utils.svg)](https://www.npmjs.com/package/@0xproject/dev-utils) | Dev utils to be shared across 0x projects and packages |
| [`@0xproject/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0xproject/json-schemas.svg)](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | [![npm](https://img.shields.io/npm/v/@0xproject/monorepo-scripts.svg)](https://www.npmjs.com/package/@0xproject/monorepo-scripts) | Monorepo scripts |
| [`@0xproject/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0xproject/order-utils.svg)](https://www.npmjs.com/package/@0xproject/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders. |
| [`@0xproject/react-docs`](/packages/react-docs) | [![npm](https://img.shields.io/npm/v/@0xproject/react-docs.svg)](https://www.npmjs.com/package/@0xproject/react-docs) | React documentation component for rendering TypeDoc & Doxity generated JSON |
| [`@0xproject/react-shared`](/packages/react-shared) | [![npm](https://img.shields.io/npm/v/@0xproject/react-shared.svg)](https://www.npmjs.com/package/@0xproject/react-shared) | 0x shared react components |
| [`@0xproject/sol-compiler`](/packages/sol-compiler) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-compiler.svg)](https://www.npmjs.com/package/@0xproject/sol-compiler) | A thin wrapper around Solc.js that outputs artifacts, resolves imports, only re-compiles when needed, and other niceties. |
| [`@0xproject/sol-cov`](/packages/sol-cov) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-cov.svg)](https://www.npmjs.com/package/@0xproject/sol-cov) | Solidity test coverage tool |
| [`@0xproject/sra-spec`](/packages/sra-spec) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-spec.svg)](https://www.npmjs.com/package/@0xproject/sra-spec) | OpenAPI specification for the standard relayer API |
| [`@0xproject/sra-report`](/packages/sra-report) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-report.svg)](https://www.npmjs.com/package/@0xproject/sra-report) | Generate reports for standard relayer API compliance |
| [`@0xproject/sol-cov`](/packages/sol-cov) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-cov.svg)](https://www.npmjs.com/package/@0xproject/sol-cov) | Solidity test coverage tool |
| [`@0xproject/subproviders`](/packages/subproviders) | [![npm](https://img.shields.io/npm/v/@0xproject/subproviders.svg)](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) |
| [`@0xproject/tslint-config`](/packages/tslint-config) | [![npm](https://img.shields.io/npm/v/@0xproject/tslint-config.svg)](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
| [`@0xproject/types`](/packages/types) | [![npm](https://img.shields.io/npm/v/@0xproject/types.svg)](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1537907159,
"version": "1.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "1.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "1.0.4",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.6 - _September 25, 2018_
* Dependencies updated
## v1.0.5 - _September 25, 2018_
* Dependencies updated
## v1.0.4 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "0x.js",
"version": "1.0.4",
"version": "1.0.6",
"engines": {
"node": ">=6.12"
},
@@ -41,9 +41,9 @@
},
"license": "Apache-2.0",
"devDependencies": {
"@0xproject/abi-gen": "^1.0.9",
"@0xproject/dev-utils": "^1.0.8",
"@0xproject/migrations": "^1.0.10",
"@0xproject/abi-gen": "^1.0.11",
"@0xproject/dev-utils": "^1.0.10",
"@0xproject/migrations": "^1.0.12",
"@0xproject/monorepo-scripts": "^1.0.9",
"@0xproject/tslint-config": "^1.0.7",
"@types/lodash": "4.14.104",
@@ -73,17 +73,17 @@
"webpack": "^3.1.0"
},
"dependencies": {
"@0xproject/assert": "^1.0.9",
"@0xproject/base-contract": "^2.0.3",
"@0xproject/contract-wrappers": "^1.0.4",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/order-watcher": "^1.0.4",
"@0xproject/subproviders": "^2.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"ethereum-types": "^1.0.7",
"@0xproject/assert": "^1.0.11",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/contract-wrappers": "^2.0.0",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/order-watcher": "^2.0.0",
"@0xproject/subproviders": "^2.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"ethereum-types": "^1.0.8",
"ethers": "3.0.22",
"lodash": "^4.17.5",
"web3-provider-engine": "14.0.6"

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1537907159,
"version": "1.0.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "1.0.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "1.0.9",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.11 - _September 25, 2018_
* Dependencies updated
## v1.0.10 - _September 25, 2018_
* Dependencies updated
## v1.0.9 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/abi-gen",
"version": "1.0.9",
"version": "1.0.11",
"engines": {
"node": ">=6.12"
},
@@ -30,10 +30,10 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
"dependencies": {
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"chalk": "^2.3.0",
"ethereum-types": "^1.0.7",
"ethereum-types": "^1.0.8",
"glob": "^7.1.2",
"handlebars": "^4.0.11",
"lodash": "^4.17.5",

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1537907159,
"version": "1.0.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "1.0.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "1.0.9",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.11 - _September 25, 2018_
* Dependencies updated
## v1.0.10 - _September 25, 2018_
* Dependencies updated
## v1.0.9 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/assert",
"version": "1.0.9",
"version": "1.0.11",
"engines": {
"node": ">=6.12"
},
@@ -44,9 +44,9 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0xproject/json-schemas": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/json-schemas": "^1.0.4",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"lodash": "^4.17.5",
"valid-url": "^1.0.9"
},

View File

@@ -0,0 +1,28 @@
[
{
"timestamp": 1537907159,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "1.0.0",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0-rc.1",
"changes": [
{
"note": "Init"
}
]
}
]

View File

@@ -0,0 +1,18 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.1 - _September 25, 2018_
* Dependencies updated
## v1.0.0 - _September 25, 2018_
* Dependencies updated
## v1.0.0-rc.1 - _Invalid date_
* Init

View File

@@ -0,0 +1,83 @@
## @0xproject/asset-buyer
Convenience package for buying assets represented on the Ethereum blockchain using 0x. In its simplest form, the package helps in the usage of the [0x forwarder contract](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md), which allows users to execute [Wrapped Ether](https://weth.io/) based 0x orders without having to set allowances, wrap Ether or buy ZRX, meaning they can buy tokens with Ether alone. Given some liquidity (0x signed orders), it helps estimate the Ether cost of buying a certain asset (giving a range) and then buying that asset.
In its more advanced and useful form, it integrates with the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api) and takes care of sourcing liquidity for you given an SRA compliant endpoint. The final result is a library that tells you what assets are available, provides an Ether based quote for any asset desired, and allows you to buy that asset using Ether alone.
## Installation
```bash
yarn add @0xproject/asset-buyer
```
**Import**
```typescript
import { AssetBuyer } from '@0xproject/asset-buyer';
```
or
```javascript
var AssetBuyer = require('@0xproject/asset-buyer').AssetBuyer;
```
If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`:
```json
"compilerOptions": {
"typeRoots": ["node_modules/@0xproject/typescript-typings/types", "node_modules/@types"],
}
```
## Contributing
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0xproject/asset-buyer yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0xproject/asset-buyer yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@@ -1,10 +1,10 @@
{
"name": "@0xproject/forwarder-helper",
"version": "1.0.4",
"name": "@0xproject/asset-buyer",
"version": "1.0.1",
"engines": {
"node": ">=6.12"
},
"description": "Convenience object for working with the forwarder contract",
"description": "Convenience package for buying assets",
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
@@ -34,21 +34,26 @@
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/forwarder-helper/README.md",
"homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md",
"dependencies": {
"@0xproject/assert": "^1.0.9",
"@0xproject/json-schemas": "^1.0.2",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@types/node": "*",
"@0xproject/assert": "^1.0.11",
"@0xproject/connect": "^2.0.4",
"@0xproject/contract-wrappers": "^2.0.0",
"@0xproject/json-schemas": "^1.0.4",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/subproviders": "^2.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"ethereum-types": "^1.0.8",
"lodash": "^4.17.10"
},
"devDependencies": {
"@0xproject/tslint-config": "^1.0.7",
"@types/lodash": "^4.14.116",
"@types/mocha": "^2.2.42",
"@types/node": "*",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",

View File

@@ -0,0 +1,324 @@
import { ContractWrappers } from '@0xproject/contract-wrappers';
import { schemas } from '@0xproject/json-schemas';
import { SignedOrder } from '@0xproject/order-utils';
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
import { constants } from './constants';
import { BasicOrderProvider } from './order_providers/basic_order_provider';
import { StandardRelayerAPIOrderProvider } from './order_providers/standard_relayer_api_order_provider';
import {
AssetBuyerError,
AssetBuyerOrdersAndFillableAmounts,
BuyQuote,
BuyQuoteRequestOpts,
OrderProvider,
OrderProviderResponse,
} from './types';
import { assert } from './utils/assert';
import { assetDataUtils } from './utils/asset_data_utils';
import { buyQuoteCalculator } from './utils/buy_quote_calculator';
import { orderProviderResponseProcessor } from './utils/order_provider_response_processor';
export class AssetBuyer {
public readonly provider: Provider;
public readonly assetData: string;
public readonly orderProvider: OrderProvider;
public readonly networkId: number;
public readonly orderRefreshIntervalMs: number;
public readonly expiryBufferSeconds: number;
private readonly _contractWrappers: ContractWrappers;
private _lastRefreshTimeIfExists?: number;
private _currentOrdersAndFillableAmountsIfExists?: AssetBuyerOrdersAndFillableAmounts;
/**
* Instantiates a new AssetBuyer instance given existing liquidity in the form of orders and feeOrders.
* @param provider The Provider instance you would like to use for interacting with the Ethereum network.
* @param orders A non-empty array of objects that conform to SignedOrder. All orders must have the same makerAssetData and takerAssetData (WETH).
* @param feeOrders A array of objects that conform to SignedOrder. All orders must have the same makerAssetData (ZRX) and takerAssetData (WETH). Defaults to an empty array.
* @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
*
* @return An instance of AssetBuyer
*/
public static getAssetBuyerForProvidedOrders(
provider: Provider,
orders: SignedOrder[],
feeOrders: SignedOrder[] = [],
networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
): AssetBuyer {
assert.isWeb3Provider('provider', provider);
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
assert.doesConformToSchema('feeOrders', feeOrders, schemas.signedOrdersSchema);
assert.isNumber('networkId', networkId);
assert.isNumber('orderRefreshIntervalMs', orderRefreshIntervalMs);
assert.areValidProvidedOrders('orders', orders);
assert.areValidProvidedOrders('feeOrders', feeOrders);
assert.assert(orders.length !== 0, `Expected orders to contain at least one order`);
const assetData = orders[0].makerAssetData;
const orderProvider = new BasicOrderProvider(_.concat(orders, feeOrders));
const assetBuyer = new AssetBuyer(
provider,
assetData,
orderProvider,
networkId,
orderRefreshIntervalMs,
expiryBufferSeconds,
);
return assetBuyer;
}
/**
* Instantiates a new AssetBuyer instance given the desired assetData and a [Standard Relayer API](https://github.com/0xProject/standard-relayer-api) endpoint
* @param provider The Provider instance you would like to use for interacting with the Ethereum network.
* @param assetData The assetData that identifies the desired asset to buy.
* @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from.
* @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
*
* @return An instance of AssetBuyer
*/
public static getAssetBuyerForAssetData(
provider: Provider,
assetData: string,
sraApiUrl: string,
networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
): AssetBuyer {
assert.isWeb3Provider('provider', provider);
assert.isHexString('assetData', assetData);
assert.isWebUri('sraApiUrl', sraApiUrl);
assert.isNumber('networkId', networkId);
assert.isNumber('orderRefreshIntervalMs', orderRefreshIntervalMs);
const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl);
const assetBuyer = new AssetBuyer(
provider,
assetData,
orderProvider,
networkId,
orderRefreshIntervalMs,
expiryBufferSeconds,
);
return assetBuyer;
}
/**
* Instantiates a new AssetBuyer instance given the desired ERC20 token address and a [Standard Relayer API](https://github.com/0xProject/standard-relayer-api) endpoint
* @param provider The Provider instance you would like to use for interacting with the Ethereum network.
* @param tokenAddress The ERC20 token address that identifies the desired asset to buy.
* @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from.
* @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
* @return An instance of AssetBuyer
*/
public static getAssetBuyerForERC20TokenAddress(
provider: Provider,
tokenAddress: string,
sraApiUrl: string,
networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
): AssetBuyer {
assert.isWeb3Provider('provider', provider);
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isWebUri('sraApiUrl', sraApiUrl);
assert.isNumber('networkId', networkId);
assert.isNumber('orderRefreshIntervalMs', orderRefreshIntervalMs);
const assetData = assetDataUtils.encodeERC20AssetData(tokenAddress);
const assetBuyer = AssetBuyer.getAssetBuyerForAssetData(
provider,
assetData,
sraApiUrl,
networkId,
orderRefreshIntervalMs,
expiryBufferSeconds,
);
return assetBuyer;
}
/**
* Instantiates a new AssetBuyer instance
* @param provider The Provider instance you would like to use for interacting with the Ethereum network.
* @param assetData The assetData of the desired asset to buy (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param orderProvider An object that conforms to OrderProvider, see type for definition.
* @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
*
* @return An instance of AssetBuyer
*/
constructor(
provider: Provider,
assetData: string,
orderProvider: OrderProvider,
networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
) {
assert.isWeb3Provider('provider', provider);
assert.isString('assetData', assetData);
assert.isValidOrderProvider('orderProvider', orderProvider);
assert.isNumber('networkId', networkId);
assert.isNumber('orderRefreshIntervalMs', orderRefreshIntervalMs);
this.provider = provider;
this.assetData = assetData;
this.orderProvider = orderProvider;
this.networkId = networkId;
this.expiryBufferSeconds = expiryBufferSeconds;
this.orderRefreshIntervalMs = orderRefreshIntervalMs;
this._contractWrappers = new ContractWrappers(this.provider, {
networkId,
});
}
/**
* Get a `BuyQuote` containing all information relevant to fulfilling a buy.
* You can then pass the `BuyQuote` to `executeBuyQuoteAsync` to execute the buy.
* @param assetBuyAmount The amount of asset to buy.
* @param feePercentage The affiliate fee percentage. Defaults to 0.
* @param forceOrderRefresh If set to true, new orders and state will be fetched instead of waiting for
* the next orderRefreshIntervalMs. Defaults to false.
* @return An object that conforms to BuyQuote that satisfies the request. See type definition for more information.
*/
public async getBuyQuoteAsync(assetBuyAmount: BigNumber, options: Partial<BuyQuoteRequestOpts>): Promise<BuyQuote> {
const { feePercentage, shouldForceOrderRefresh, slippagePercentage } = {
...options,
...constants.DEFAULT_BUY_QUOTE_REQUEST_OPTS,
};
assert.isBigNumber('assetBuyAmount', assetBuyAmount);
assert.isValidPercentage('feePercentage', feePercentage);
assert.isBoolean('shouldForceOrderRefresh', shouldForceOrderRefresh);
// we should refresh if:
// we do not have any orders OR
// we are forced to OR
// we have some last refresh time AND that time was sufficiently long ago
const shouldRefresh =
_.isUndefined(this._currentOrdersAndFillableAmountsIfExists) ||
shouldForceOrderRefresh ||
(!_.isUndefined(this._lastRefreshTimeIfExists) &&
this._lastRefreshTimeIfExists + this.orderRefreshIntervalMs < Date.now());
let ordersAndFillableAmounts: AssetBuyerOrdersAndFillableAmounts;
if (shouldRefresh) {
ordersAndFillableAmounts = await this._getLatestOrdersAndFillableAmountsAsync();
this._lastRefreshTimeIfExists = Date.now();
this._currentOrdersAndFillableAmountsIfExists = ordersAndFillableAmounts;
} else {
// it is safe to cast to AssetBuyerOrdersAndFillableAmounts because shouldRefresh catches the undefined case above
ordersAndFillableAmounts = this
._currentOrdersAndFillableAmountsIfExists as AssetBuyerOrdersAndFillableAmounts;
}
const buyQuote = buyQuoteCalculator.calculate(
ordersAndFillableAmounts,
assetBuyAmount,
feePercentage,
slippagePercentage,
);
return buyQuote;
}
/**
* Given a BuyQuote and desired rate, attempt to execute the buy.
* @param buyQuote An object that conforms to BuyQuote. See type definition for more information.
* @param rate The desired rate to execute the buy at. Affects the amount of ETH sent with the transaction, defaults to buyQuote.maxRate.
* @param takerAddress The address to perform the buy. Defaults to the first available address from the provider.
* @param feeRecipient The address where affiliate fees are sent. Defaults to null address (0x000...000).
* @return A promise of the txHash.
*/
public async executeBuyQuoteAsync(
buyQuote: BuyQuote,
rate?: BigNumber,
takerAddress?: string,
feeRecipient: string = constants.NULL_ADDRESS,
): Promise<string> {
assert.isValidBuyQuote('buyQuote', buyQuote);
if (!_.isUndefined(rate)) {
assert.isBigNumber('rate', rate);
}
if (!_.isUndefined(takerAddress)) {
assert.isETHAddressHex('takerAddress', takerAddress);
}
assert.isETHAddressHex('feeRecipient', feeRecipient);
const { orders, feeOrders, feePercentage, assetBuyAmount, maxRate } = buyQuote;
// if no takerAddress is provided, try to get one from the provider
let finalTakerAddress;
if (!_.isUndefined(takerAddress)) {
finalTakerAddress = takerAddress;
} else {
const web3Wrapper = new Web3Wrapper(this.provider);
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
const firstAvailableAddress = _.head(availableAddresses);
if (!_.isUndefined(firstAvailableAddress)) {
finalTakerAddress = firstAvailableAddress;
} else {
throw new Error(AssetBuyerError.NoAddressAvailable);
}
}
// if no rate is provided, default to the maxRate from buyQuote
const desiredRate = rate || maxRate;
// calculate how much eth is required to buy assetBuyAmount at the desired rate
const ethAmount = assetBuyAmount.dividedToIntegerBy(desiredRate);
const txHash = await this._contractWrappers.forwarder.marketBuyOrdersWithEthAsync(
orders,
assetBuyAmount,
finalTakerAddress,
ethAmount,
feeOrders,
feePercentage,
feeRecipient,
);
return txHash;
}
/**
* Ask the order Provider for orders and process them.
*/
private async _getLatestOrdersAndFillableAmountsAsync(): Promise<AssetBuyerOrdersAndFillableAmounts> {
const etherTokenAssetData = this._getEtherTokenAssetDataOrThrow();
const zrxTokenAssetData = this._getZrxTokenAssetDataOrThrow();
// construct order Provider requests
const targetOrderProviderRequest = {
makerAssetData: this.assetData,
takerAssetData: etherTokenAssetData,
networkId: this.networkId,
};
const feeOrderProviderRequest = {
makerAssetData: zrxTokenAssetData,
takerAssetData: etherTokenAssetData,
networkId: this.networkId,
};
const requests = [targetOrderProviderRequest, feeOrderProviderRequest];
// fetch orders and possible fillable amounts
const [targetOrderProviderResponse, feeOrderProviderResponse] = await Promise.all(
_.map(requests, async request => this.orderProvider.getOrdersAsync(request)),
);
// since the order provider is an injected dependency, validate that it respects the API
// ie. it should only return maker/taker assetDatas that are specified
orderProviderResponseProcessor.throwIfInvalidResponse(targetOrderProviderResponse, targetOrderProviderRequest);
orderProviderResponseProcessor.throwIfInvalidResponse(feeOrderProviderResponse, feeOrderProviderRequest);
// process the responses into one object
const ordersAndFillableAmounts = await orderProviderResponseProcessor.processAsync(
targetOrderProviderResponse,
feeOrderProviderResponse,
zrxTokenAssetData,
this.expiryBufferSeconds,
this._contractWrappers.orderValidator,
);
return ordersAndFillableAmounts;
}
/**
* Get the assetData that represents the WETH token.
* Will throw if WETH does not exist for the current network.
*/
private _getEtherTokenAssetDataOrThrow(): string {
return assetDataUtils.getEtherTokenAssetDataOrThrow(this._contractWrappers);
}
/**
* Get the assetData that represents the ZRX token.
* Will throw if ZRX does not exist for the current network.
*/
private _getZrxTokenAssetDataOrThrow(): string {
return assetDataUtils.getZrxTokenAssetDataOrThrow(this._contractWrappers);
}
}

View File

@@ -0,0 +1,20 @@
import { BigNumber } from '@0xproject/utils';
import { BuyQuoteRequestOpts } from './types';
const DEFAULT_BUY_QUOTE_REQUEST_OPTS: BuyQuoteRequestOpts = {
feePercentage: 0,
shouldForceOrderRefresh: false,
slippagePercentage: 0.2, // 20% slippage protection
};
export const constants = {
ZERO_AMOUNT: new BigNumber(0),
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
MAINNET_NETWORK_ID: 1,
DEFAULT_ORDER_REFRESH_INTERVAL_MS: 10000, // 10 seconds
ETHER_TOKEN_DECIMALS: 18,
DEFAULT_BUY_QUOTE_REQUEST_OPTS,
MAX_PER_PAGE: 10000,
DEFAULT_EXPIRY_BUFFER_SECONDS: 15,
};

View File

@@ -0,0 +1,17 @@
export { Provider } from 'ethereum-types';
export { SignedOrder } from '@0xproject/types';
export { BigNumber } from '@0xproject/utils';
export { AssetBuyer } from './asset_buyer';
export { BasicOrderProvider } from './order_providers/basic_order_provider';
export { StandardRelayerAPIOrderProvider } from './order_providers/standard_relayer_api_order_provider';
export { StandardRelayerAPIAssetBuyerManager } from './standard_relayer_api_asset_buyer_manager';
export {
AssetBuyerError,
BuyQuote,
OrderProvider,
OrderProviderRequest,
OrderProviderResponse,
SignedOrderWithRemainingFillableMakerAssetAmount,
StandardRelayerApiAssetBuyerManagerError,
} from './types';

View File

@@ -0,0 +1,32 @@
import { schemas } from '@0xproject/json-schemas';
import { SignedOrder } from '@0xproject/types';
import * as _ from 'lodash';
import { OrderProvider, OrderProviderRequest, OrderProviderResponse } from '../types';
import { assert } from '../utils/assert';
export class BasicOrderProvider implements OrderProvider {
public readonly orders: SignedOrder[];
/**
* Instantiates a new BasicOrderProvider instance
* @param orders An array of objects that conform to SignedOrder to fetch from.
* @return An instance of BasicOrderProvider
*/
constructor(orders: SignedOrder[]) {
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
this.orders = orders;
}
/**
* Given an object that conforms to OrderFetcherRequest, return the corresponding OrderProviderResponse that satisfies the request.
* @param orderProviderRequest An instance of OrderFetcherRequest. See type for more information.
* @return An instance of OrderProviderResponse. See type for more information.
*/
public async getOrdersAsync(orderProviderRequest: OrderProviderRequest): Promise<OrderProviderResponse> {
assert.isValidOrderProviderRequest('orderProviderRequest', orderProviderRequest);
const { makerAssetData, takerAssetData } = orderProviderRequest;
const orders = _.filter(this.orders, order => {
return order.makerAssetData === makerAssetData && order.takerAssetData === takerAssetData;
});
return { orders };
}
}

View File

@@ -0,0 +1,79 @@
import { HttpClient } from '@0xproject/connect';
import { APIOrder, OrderbookResponse } from '@0xproject/types';
import * as _ from 'lodash';
import {
AssetBuyerError,
OrderProvider,
OrderProviderRequest,
OrderProviderResponse,
SignedOrderWithRemainingFillableMakerAssetAmount,
} from '../types';
import { assert } from '../utils/assert';
import { orderUtils } from '../utils/order_utils';
export class StandardRelayerAPIOrderProvider implements OrderProvider {
public readonly apiUrl: string;
private readonly _sraClient: HttpClient;
/**
* Given an array of APIOrder objects from a standard relayer api, return an array
* of SignedOrderWithRemainingFillableMakerAssetAmounts
*/
private static _getSignedOrderWithRemainingFillableMakerAssetAmountFromApi(
apiOrders: APIOrder[],
): SignedOrderWithRemainingFillableMakerAssetAmount[] {
const result = _.map(apiOrders, apiOrder => {
const { order, metaData } = apiOrder;
// calculate remainingFillableMakerAssetAmount from api metadata, else assume order is completely fillable
const remainingFillableTakerAssetAmount = _.get(
metaData,
'remainingTakerAssetAmount',
order.takerAssetAmount,
);
const remainingFillableMakerAssetAmount = orderUtils.calculateRemainingMakerAssetAmount(
order,
remainingFillableTakerAssetAmount,
);
const newOrder = {
...order,
remainingFillableMakerAssetAmount,
};
return newOrder;
});
return result;
}
/**
* Instantiates a new StandardRelayerAPIOrderProvider instance
* @param apiUrl The standard relayer API base HTTP url you would like to source orders from.
* @return An instance of StandardRelayerAPIOrderProvider
*/
constructor(apiUrl: string) {
assert.isWebUri('apiUrl', apiUrl);
this.apiUrl = apiUrl;
this._sraClient = new HttpClient(apiUrl);
}
/**
* Given an object that conforms to OrderProviderRequest, return the corresponding OrderProviderResponse that satisfies the request.
* @param orderProviderRequest An instance of OrderProviderRequest. See type for more information.
* @return An instance of OrderProviderResponse. See type for more information.
*/
public async getOrdersAsync(orderProviderRequest: OrderProviderRequest): Promise<OrderProviderResponse> {
assert.isValidOrderProviderRequest('orderProviderRequest', orderProviderRequest);
const { makerAssetData, takerAssetData, networkId } = orderProviderRequest;
const orderbookRequest = { baseAssetData: makerAssetData, quoteAssetData: takerAssetData };
const requestOpts = { networkId };
let orderbook: OrderbookResponse;
try {
orderbook = await this._sraClient.getOrderbookAsync(orderbookRequest, requestOpts);
} catch (err) {
throw new Error(AssetBuyerError.StandardRelayerApiError);
}
const apiOrders = orderbook.asks.records;
const orders = StandardRelayerAPIOrderProvider._getSignedOrderWithRemainingFillableMakerAssetAmountFromApi(
apiOrders,
);
return {
orders,
};
}
}

View File

@@ -0,0 +1,133 @@
import { HttpClient } from '@0xproject/connect';
import { ContractWrappers } from '@0xproject/contract-wrappers';
import { ObjectMap } from '@0xproject/types';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
import { AssetBuyer } from './asset_buyer';
import { constants } from './constants';
import { assert } from './utils/assert';
import { assetDataUtils } from './utils/asset_data_utils';
import { OrderProvider, StandardRelayerApiAssetBuyerManagerError } from './types';
export class StandardRelayerAPIAssetBuyerManager {
// Map of assetData to AssetBuyer for that assetData
private readonly _assetBuyerMap: ObjectMap<AssetBuyer>;
/**
* Returns an array of all assetDatas available at the provided sraApiUrl
* @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from.
* @param pairedWithAssetData Optional filter argument to return assetDatas that only pair with this assetData value.
*
* @return An array of all assetDatas available at the provider sraApiUrl
*/
public static async getAllAvailableAssetDatasAsync(
sraApiUrl: string,
pairedWithAssetData?: string,
): Promise<string[]> {
const client = new HttpClient(sraApiUrl);
const params = {
assetDataA: pairedWithAssetData,
perPage: constants.MAX_PER_PAGE,
};
const assetPairsResponse = await client.getAssetPairsAsync(params);
return _.uniq(_.map(assetPairsResponse.records, pairsItem => pairsItem.assetDataB.assetData));
}
/**
* Instantiates a new StandardRelayerAPIAssetBuyerManager instance with all available assetDatas at the provided sraApiUrl
* @param provider The Provider instance you would like to use for interacting with the Ethereum network.
* @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from.
* @param orderProvider An object that conforms to OrderProvider, see type for definition.
* @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states.
* Defaults to 10000ms (10s).
* @return An promise of an instance of StandardRelayerAPIAssetBuyerManager
*/
public static async getAssetBuyerManagerWithAllAvailableAssetDatasAsync(
provider: Provider,
sraApiUrl: string,
orderProvider: OrderProvider,
networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs?: number,
): Promise<StandardRelayerAPIAssetBuyerManager> {
const contractWrappers = new ContractWrappers(provider, { networkId });
const etherTokenAssetData = assetDataUtils.getEtherTokenAssetDataOrThrow(contractWrappers);
const assetDatas = await StandardRelayerAPIAssetBuyerManager.getAllAvailableAssetDatasAsync(
sraApiUrl,
etherTokenAssetData,
);
return new StandardRelayerAPIAssetBuyerManager(
provider,
assetDatas,
orderProvider,
networkId,
orderRefreshIntervalMs,
);
}
/**
* Instantiates a new StandardRelayerAPIAssetBuyerManager instance
* @param provider The Provider instance you would like to use for interacting with the Ethereum network.
* @param assetDatas The assetDatas of the desired assets to buy (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param orderProvider An object that conforms to OrderProvider, see type for definition.
* @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states.
* Defaults to 10000ms (10s).
* @return An instance of StandardRelayerAPIAssetBuyerManager
*/
constructor(
provider: Provider,
assetDatas: string[],
orderProvider: OrderProvider,
networkId?: number,
orderRefreshIntervalMs?: number,
) {
assert.assert(assetDatas.length > 0, `Expected 'assetDatas' to be a non-empty array.`);
this._assetBuyerMap = _.reduce(
assetDatas,
(accAssetBuyerMap: ObjectMap<AssetBuyer>, assetData: string) => {
accAssetBuyerMap[assetData] = new AssetBuyer(
provider,
assetData,
orderProvider,
networkId,
orderRefreshIntervalMs,
);
return accAssetBuyerMap;
},
{},
);
}
/**
* Get an AssetBuyer for the provided assetData
* @param assetData The desired assetData.
*
* @return An instance of AssetBuyer
*/
public getAssetBuyerFromAssetData(assetData: string): AssetBuyer {
const assetBuyer = this._assetBuyerMap[assetData];
if (_.isUndefined(assetBuyer)) {
throw new Error(
`${StandardRelayerApiAssetBuyerManagerError.AssetBuyerNotFound}: For assetData ${assetData}`,
);
}
return assetBuyer;
}
/**
* Get an AssetBuyer for the provided ERC20 tokenAddress
* @param tokenAddress The desired tokenAddress.
*
* @return An instance of AssetBuyer
*/
public getAssetBuyerFromERC20TokenAddress(tokenAddress: string): AssetBuyer {
const assetData = assetDataUtils.encodeERC20AssetData(tokenAddress);
return this.getAssetBuyerFromAssetData(assetData);
}
/**
* Get a list of all the assetDatas that the instance supports
*
* @return An array of assetData strings
*/
public getAssetDatas(): string[] {
return _.keys(this._assetBuyerMap);
}
}

View File

@@ -0,0 +1,86 @@
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
/**
* makerAssetData: The assetData representing the desired makerAsset.
* takerAssetData: The assetData representing the desired takerAsset.
* networkId: The networkId that the desired orders should be for.
*/
export interface OrderProviderRequest {
makerAssetData: string;
takerAssetData: string;
networkId: number;
}
/**
* orders: An array of orders with optional remaining fillable makerAsset amounts. See type for more info.
*/
export interface OrderProviderResponse {
orders: SignedOrderWithRemainingFillableMakerAssetAmount[];
}
/**
* A normal SignedOrder with one extra optional property `remainingFillableMakerAssetAmount`
* remainingFillableMakerAssetAmount: The amount of the makerAsset that is available to be filled
*/
export interface SignedOrderWithRemainingFillableMakerAssetAmount extends SignedOrder {
remainingFillableMakerAssetAmount?: BigNumber;
}
/**
* Given an OrderProviderRequest, get an OrderProviderResponse.
*/
export interface OrderProvider {
getOrdersAsync: (orderProviderRequest: OrderProviderRequest) => Promise<OrderProviderResponse>;
}
/**
* assetData: String that represents a specific asset (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* orders: An array of objects conforming to SignedOrder. These orders can be used to cover the requested assetBuyAmount plus slippage.
* feeOrders: An array of objects conforming to SignedOrder. These orders can be used to cover the fees for the orders param above.
* minRate: Min rate that needs to be paid in order to execute the buy.
* maxRate: Max rate that can be paid in order to execute the buy.
* assetBuyAmount: The amount of asset to buy.
* feePercentage: Optional affiliate fee percentage used to calculate the eth amounts above.
*/
export interface BuyQuote {
assetData: string;
orders: SignedOrder[];
feeOrders: SignedOrder[];
minRate: BigNumber;
maxRate: BigNumber;
assetBuyAmount: BigNumber;
feePercentage?: number;
}
export interface BuyQuoteRequestOpts {
feePercentage: number;
shouldForceOrderRefresh: boolean;
slippagePercentage: number;
}
/**
* Possible errors thrown by an AssetBuyer instance or associated static methods.
*/
export enum AssetBuyerError {
NoEtherTokenContractFound = 'NO_ETHER_TOKEN_CONTRACT_FOUND',
NoZrxTokenContractFound = 'NO_ZRX_TOKEN_CONTRACT_FOUND',
StandardRelayerApiError = 'STANDARD_RELAYER_API_ERROR',
InsufficientAssetLiquidity = 'INSUFFICIENT_ASSET_LIQUIDITY',
InsufficientZrxLiquidity = 'INSUFFICIENT_ZRX_LIQUIDITY',
NoAddressAvailable = 'NO_ADDRESS_AVAILABLE',
InvalidOrderProviderResponse = 'INVALID_ORDER_PROVIDER_RESPONSE',
}
/**
* Possible errors thrown by an StandardRelayerApiAssetBuyerManager instance or associated static methods.
*/
export enum StandardRelayerApiAssetBuyerManagerError {
AssetBuyerNotFound = 'ASSET_BUYER_NOT_FOUND',
}
export interface AssetBuyerOrdersAndFillableAmounts {
orders: SignedOrder[];
feeOrders: SignedOrder[];
remainingFillableMakerAssetAmounts: BigNumber[];
remainingFillableFeeAmounts: BigNumber[];
}

View File

@@ -0,0 +1,51 @@
import { assert as sharedAssert } from '@0xproject/assert';
import { schemas } from '@0xproject/json-schemas';
import { SignedOrder } from '@0xproject/types';
import * as _ from 'lodash';
import { BuyQuote, OrderProvider, OrderProviderRequest } from '../types';
export const assert = {
...sharedAssert,
isValidBuyQuote(variableName: string, buyQuote: BuyQuote): void {
sharedAssert.isHexString(`${variableName}.assetData`, buyQuote.assetData);
sharedAssert.doesConformToSchema(`${variableName}.orders`, buyQuote.orders, schemas.signedOrdersSchema);
sharedAssert.doesConformToSchema(`${variableName}.feeOrders`, buyQuote.feeOrders, schemas.signedOrdersSchema);
sharedAssert.isBigNumber(`${variableName}.minRate`, buyQuote.minRate);
sharedAssert.isBigNumber(`${variableName}.maxRate`, buyQuote.maxRate);
sharedAssert.isBigNumber(`${variableName}.assetBuyAmount`, buyQuote.assetBuyAmount);
if (!_.isUndefined(buyQuote.feePercentage)) {
sharedAssert.isNumber(`${variableName}.feePercentage`, buyQuote.feePercentage);
}
},
isValidOrderProvider(variableName: string, orderFetcher: OrderProvider): void {
sharedAssert.isFunction(`${variableName}.getOrdersAsync`, orderFetcher.getOrdersAsync);
},
isValidOrderProviderRequest(variableName: string, orderFetcherRequest: OrderProviderRequest): void {
sharedAssert.isHexString(`${variableName}.makerAssetData`, orderFetcherRequest.makerAssetData);
sharedAssert.isHexString(`${variableName}.takerAssetData`, orderFetcherRequest.takerAssetData);
sharedAssert.isNumber(`${variableName}.networkId`, orderFetcherRequest.networkId);
},
areValidProvidedOrders(variableName: string, orders: SignedOrder[]): void {
if (orders.length === 0) {
return;
}
const makerAssetData = orders[0].makerAssetData;
const takerAssetData = orders[0].takerAssetData;
const filteredOrders = _.filter(
orders,
order => order.makerAssetData === makerAssetData && order.takerAssetData === takerAssetData,
);
sharedAssert.assert(
orders.length === filteredOrders.length,
`Expected all orders in ${variableName} to have the same makerAssetData and takerAssetData.`,
);
},
isValidPercentage(variableName: string, percentage: number): void {
assert.isNumber(variableName, percentage);
assert.assert(
percentage >= 0 && percentage <= 1,
`Expected ${variableName} to be between 0 and 1, but is ${percentage}`,
);
},
};

View File

@@ -0,0 +1,26 @@
import { ContractWrappers } from '@0xproject/contract-wrappers';
import { assetDataUtils as sharedAssetDataUtils } from '@0xproject/order-utils';
import * as _ from 'lodash';
import { AssetBuyerError } from '../types';
export const assetDataUtils = {
...sharedAssetDataUtils,
getEtherTokenAssetDataOrThrow(contractWrappers: ContractWrappers): string {
const etherTokenAddressIfExists = contractWrappers.etherToken.getContractAddressIfExists();
if (_.isUndefined(etherTokenAddressIfExists)) {
throw new Error(AssetBuyerError.NoEtherTokenContractFound);
}
const etherTokenAssetData = sharedAssetDataUtils.encodeERC20AssetData(etherTokenAddressIfExists);
return etherTokenAssetData;
},
getZrxTokenAssetDataOrThrow(contractWrappers: ContractWrappers): string {
let zrxTokenAssetData: string;
try {
zrxTokenAssetData = contractWrappers.exchange.getZRXAssetData();
} catch (err) {
throw new Error(AssetBuyerError.NoZrxTokenContractFound);
}
return zrxTokenAssetData;
},
};

View File

@@ -0,0 +1,89 @@
import { marketUtils } from '@0xproject/order-utils';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import { constants } from '../constants';
import { AssetBuyerError, AssetBuyerOrdersAndFillableAmounts, BuyQuote } from '../types';
import { orderUtils } from './order_utils';
// Calculates a buy quote for orders that have WETH as the takerAsset
export const buyQuoteCalculator = {
calculate(
ordersAndFillableAmounts: AssetBuyerOrdersAndFillableAmounts,
assetBuyAmount: BigNumber,
feePercentage: number,
slippagePercentage: number,
): BuyQuote {
const {
orders,
feeOrders,
remainingFillableMakerAssetAmounts,
remainingFillableFeeAmounts,
} = ordersAndFillableAmounts;
const slippageBufferAmount = assetBuyAmount.mul(slippagePercentage).round();
const {
resultOrders,
remainingFillAmount,
ordersRemainingFillableMakerAssetAmounts,
} = marketUtils.findOrdersThatCoverMakerAssetFillAmount(orders, assetBuyAmount, {
remainingFillableMakerAssetAmounts,
slippageBufferAmount,
});
if (remainingFillAmount.gt(constants.ZERO_AMOUNT)) {
throw new Error(AssetBuyerError.InsufficientAssetLiquidity);
}
// TODO(bmillman): optimization
// update this logic to find the minimum amount of feeOrders to cover the worst case as opposed to
// finding order that cover all fees, this will help with estimating ETH and minimizing gas usage
const {
resultFeeOrders,
remainingFeeAmount,
feeOrdersRemainingFillableMakerAssetAmounts,
} = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(resultOrders, feeOrders, {
remainingFillableMakerAssetAmounts,
remainingFillableFeeAmounts,
});
if (remainingFeeAmount.gt(constants.ZERO_AMOUNT)) {
throw new Error(AssetBuyerError.InsufficientZrxLiquidity);
}
const assetData = orders[0].makerAssetData;
// calculate minRate and maxRate by calculating min and max eth usage and then dividing into
// assetBuyAmount to get assetData / WETH, needs to take into account feePercentage as well
// minEthAmount = (sum(takerAssetAmount[i]) until sum(makerAssetAmount[i]) >= assetBuyAmount ) * (1 + feePercentage)
// maxEthAmount = (sum(takerAssetAmount[i]) until i == orders.length) * (1 + feePercentage)
const allOrders = _.concat(resultOrders, resultFeeOrders);
const allRemainingAmounts = _.concat(
ordersRemainingFillableMakerAssetAmounts,
feeOrdersRemainingFillableMakerAssetAmounts,
);
let minEthAmount = constants.ZERO_AMOUNT;
let maxEthAmount = constants.ZERO_AMOUNT;
let cumulativeMakerAmount = constants.ZERO_AMOUNT;
_.forEach(allOrders, (order, index) => {
const remainingFillableMakerAssetAmount = allRemainingAmounts[index];
const claimableTakerAssetAmount = orderUtils.calculateRemainingTakerAssetAmount(
order,
remainingFillableMakerAssetAmount,
);
// taker asset is always assumed to be WETH
maxEthAmount = maxEthAmount.plus(claimableTakerAssetAmount);
if (cumulativeMakerAmount.lessThan(assetBuyAmount)) {
minEthAmount = minEthAmount.plus(claimableTakerAssetAmount);
}
cumulativeMakerAmount = cumulativeMakerAmount.plus(remainingFillableMakerAssetAmount);
});
const feeAdjustedMinRate = minEthAmount.mul(feePercentage + 1).div(assetBuyAmount);
const feeAdjustedMaxRate = minEthAmount.mul(feePercentage + 1).div(assetBuyAmount);
return {
assetData,
orders: resultOrders,
feeOrders: resultFeeOrders,
minRate: feeAdjustedMinRate,
maxRate: feeAdjustedMaxRate,
assetBuyAmount,
feePercentage,
};
},
};

View File

@@ -0,0 +1,202 @@
import { OrderAndTraderInfo, OrderStatus, OrderValidatorWrapper } from '@0xproject/contract-wrappers';
import { sortingUtils } from '@0xproject/order-utils';
import { RemainingFillableCalculator } from '@0xproject/order-utils/lib/src/remaining_fillable_calculator';
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import { constants } from '../constants';
import {
AssetBuyerError,
AssetBuyerOrdersAndFillableAmounts,
OrderProviderRequest,
OrderProviderResponse,
SignedOrderWithRemainingFillableMakerAssetAmount,
} from '../types';
import { orderUtils } from './order_utils';
interface OrdersAndRemainingFillableMakerAssetAmounts {
orders: SignedOrder[];
remainingFillableMakerAssetAmounts: BigNumber[];
}
export const orderProviderResponseProcessor = {
throwIfInvalidResponse(response: OrderProviderResponse, request: OrderProviderRequest): void {
const { makerAssetData, takerAssetData } = request;
_.forEach(response.orders, order => {
if (order.makerAssetData !== makerAssetData || order.takerAssetData !== takerAssetData) {
throw new Error(AssetBuyerError.InvalidOrderProviderResponse);
}
});
},
/**
* Take the responses for the target orders to buy and fee orders and process them.
* Processing includes:
* - Drop orders that are expired or not open orders (null taker address)
* - If shouldValidateOnChain, attempt to grab fillable amounts from on-chain otherwise assume completely fillable
* - Sort by rate
*/
async processAsync(
targetOrderProviderResponse: OrderProviderResponse,
feeOrderProviderResponse: OrderProviderResponse,
zrxTokenAssetData: string,
expiryBufferSeconds: number,
orderValidator?: OrderValidatorWrapper,
): Promise<AssetBuyerOrdersAndFillableAmounts> {
// drop orders that are expired or not open
const filteredTargetOrders = filterOutExpiredAndNonOpenOrders(
targetOrderProviderResponse.orders,
expiryBufferSeconds,
);
const filteredFeeOrders = filterOutExpiredAndNonOpenOrders(
feeOrderProviderResponse.orders,
expiryBufferSeconds,
);
// set the orders to be sorted equal to the filtered orders
let unsortedTargetOrders = filteredTargetOrders;
let unsortedFeeOrders = filteredFeeOrders;
// if an orderValidator is provided, use on chain information to calculate remaining fillable makerAsset amounts
if (!_.isUndefined(orderValidator)) {
// TODO(bmillman): improvement
// try/catch these requests and throw a more domain specific error
// TODO(bmillman): optimization
// reduce this to once RPC call buy combining orders into one array and then splitting up the response
const [targetOrdersAndTradersInfo, feeOrdersAndTradersInfo] = await Promise.all(
_.map([filteredTargetOrders, filteredFeeOrders], ordersToBeValidated => {
const takerAddresses = _.map(ordersToBeValidated, () => constants.NULL_ADDRESS);
return orderValidator.getOrdersAndTradersInfoAsync(ordersToBeValidated, takerAddresses);
}),
);
// take orders + on chain information and find the valid orders and remaining fillable maker asset amounts
unsortedTargetOrders = getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain(
filteredTargetOrders,
targetOrdersAndTradersInfo,
zrxTokenAssetData,
);
// take orders + on chain information and find the valid orders and remaining fillable maker asset amounts
unsortedFeeOrders = getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain(
filteredFeeOrders,
feeOrdersAndTradersInfo,
zrxTokenAssetData,
);
}
// sort orders by rate
// TODO(bmillman): optimization
// provide a feeRate to the sorting function to more accurately sort based on the current market for ZRX tokens
const sortedTargetOrders = sortingUtils.sortOrdersByFeeAdjustedRate(unsortedTargetOrders);
const sortedFeeOrders = sortingUtils.sortFeeOrdersByFeeAdjustedRate(unsortedFeeOrders);
// unbundle orders and fillable amounts and compile final result
const targetOrdersAndRemainingFillableMakerAssetAmounts = unbundleOrdersWithAmounts(sortedTargetOrders);
const feeOrdersAndRemainingFillableMakerAssetAmounts = unbundleOrdersWithAmounts(sortedFeeOrders);
return {
orders: targetOrdersAndRemainingFillableMakerAssetAmounts.orders,
feeOrders: feeOrdersAndRemainingFillableMakerAssetAmounts.orders,
remainingFillableMakerAssetAmounts:
targetOrdersAndRemainingFillableMakerAssetAmounts.remainingFillableMakerAssetAmounts,
remainingFillableFeeAmounts:
feeOrdersAndRemainingFillableMakerAssetAmounts.remainingFillableMakerAssetAmounts,
};
},
};
/**
* Given an array of orders, return a new array with expired and non open orders filtered out.
*/
function filterOutExpiredAndNonOpenOrders(
orders: SignedOrderWithRemainingFillableMakerAssetAmount[],
expiryBufferSeconds: number,
): SignedOrderWithRemainingFillableMakerAssetAmount[] {
const result = _.filter(orders, order => {
return orderUtils.isOpenOrder(order) && !orderUtils.willOrderExpire(order, expiryBufferSeconds);
});
return result;
}
/**
* Given an array of orders and corresponding on-chain infos, return a subset of the orders
* that are still fillable orders with their corresponding remainingFillableMakerAssetAmounts.
*/
function getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain(
inputOrders: SignedOrder[],
ordersAndTradersInfo: OrderAndTraderInfo[],
zrxAssetData: string,
): SignedOrderWithRemainingFillableMakerAssetAmount[] {
// iterate through the input orders and find the ones that are still fillable
// for the orders that are still fillable, calculate the remaining fillable maker asset amount
const result = _.reduce(
inputOrders,
(accOrders, order, index) => {
// get corresponding on-chain state for the order
const { orderInfo, traderInfo } = ordersAndTradersInfo[index];
// if the order IS NOT fillable, do not add anything to the accumulations and continue iterating
if (orderInfo.orderStatus !== OrderStatus.FILLABLE) {
return accOrders;
}
// if the order IS fillable, add the order and calculate the remaining fillable amount
const transferrableAssetAmount = BigNumber.min([traderInfo.makerAllowance, traderInfo.makerBalance]);
const transferrableFeeAssetAmount = BigNumber.min([
traderInfo.makerZrxAllowance,
traderInfo.makerZrxBalance,
]);
const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount);
const remainingMakerAssetAmount = orderUtils.calculateRemainingMakerAssetAmount(
order,
remainingTakerAssetAmount,
);
const remainingFillableCalculator = new RemainingFillableCalculator(
order.makerFee,
order.makerAssetAmount,
order.makerAssetData === zrxAssetData,
transferrableAssetAmount,
transferrableFeeAssetAmount,
remainingMakerAssetAmount,
);
const remainingFillableAmount = remainingFillableCalculator.computeRemainingFillable();
// if the order does not have any remaining fillable makerAsset, do not add anything to the accumulations and continue iterating
if (remainingFillableAmount.lte(constants.ZERO_AMOUNT)) {
return accOrders;
}
const orderWithRemainingFillableMakerAssetAmount = {
...order,
remainingFillableMakerAssetAmount: remainingFillableAmount,
};
const newAccOrders = _.concat(accOrders, orderWithRemainingFillableMakerAssetAmount);
return newAccOrders;
},
[] as SignedOrderWithRemainingFillableMakerAssetAmount[],
);
return result;
}
/**
* Given an array of orders with remaining fillable maker asset amounts. Unbundle into an instance of OrdersAndRemainingFillableMakerAssetAmounts.
* If an order is missing a corresponding remainingFillableMakerAssetAmount, assume it is completely fillable.
*/
function unbundleOrdersWithAmounts(
ordersWithAmounts: SignedOrderWithRemainingFillableMakerAssetAmount[],
): OrdersAndRemainingFillableMakerAssetAmounts {
const result = _.reduce(
ordersWithAmounts,
(acc, orderWithAmount) => {
const { orders, remainingFillableMakerAssetAmounts } = acc;
const { remainingFillableMakerAssetAmount, ...order } = orderWithAmount;
// if we are still missing a remainingFillableMakerAssetAmount, assume the order is completely fillable
const newRemainingAmount = remainingFillableMakerAssetAmount || order.makerAssetAmount;
// if remaining amount is less than or equal to zero, do not add it
if (newRemainingAmount.lte(constants.ZERO_AMOUNT)) {
return acc;
}
const newAcc = {
orders: _.concat(orders, order),
remainingFillableMakerAssetAmounts: _.concat(remainingFillableMakerAssetAmounts, newRemainingAmount),
};
return newAcc;
},
{
orders: [] as SignedOrder[],
remainingFillableMakerAssetAmounts: [] as BigNumber[],
},
);
return result;
}

View File

@@ -0,0 +1,30 @@
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { constants } from '../constants';
export const orderUtils = {
isOrderExpired(order: SignedOrder): boolean {
return orderUtils.willOrderExpire(order, 0);
},
willOrderExpire(order: SignedOrder, secondsFromNow: number): boolean {
const millisecondsInSecond = 1000;
const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).round();
return order.expirationTimeSeconds.lessThan(currentUnixTimestampSec.minus(secondsFromNow));
},
calculateRemainingMakerAssetAmount(order: SignedOrder, remainingTakerAssetAmount: BigNumber): BigNumber {
if (remainingTakerAssetAmount.eq(0)) {
return constants.ZERO_AMOUNT;
}
return remainingTakerAssetAmount.times(order.makerAssetAmount).dividedToIntegerBy(order.takerAssetAmount);
},
calculateRemainingTakerAssetAmount(order: SignedOrder, remainingMakerAssetAmount: BigNumber): BigNumber {
if (remainingMakerAssetAmount.eq(0)) {
return constants.ZERO_AMOUNT;
}
return remainingMakerAssetAmount.times(order.takerAssetAmount).dividedToIntegerBy(order.makerAssetAmount);
},
isOpenOrder(order: SignedOrder): boolean {
return order.takerAddress === constants.NULL_ADDRESS;
},
};

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1537907159,
"version": "2.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "2.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "2.0.3",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.5 - _September 25, 2018_
* Dependencies updated
## v2.0.4 - _September 25, 2018_
* Dependencies updated
## v2.0.3 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/base-contract",
"version": "2.0.3",
"version": "2.0.5",
"engines": {
"node": ">=6.12"
},
@@ -40,10 +40,10 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"ethereum-types": "^1.0.7",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"ethereum-types": "^1.0.8",
"ethers": "3.0.22",
"lodash": "^4.17.5"
},

View File

@@ -1,4 +1,23 @@
[
{
"timestamp": 1537907159,
"version": "2.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.0.3",
"changes": [
{
"note": "Import SRA-related types from @0xproject/types",
"pr": 1085
}
],
"timestamp": 1537875740
},
{
"timestamp": 1537541580,
"version": "2.0.2",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.4 - _September 25, 2018_
* Dependencies updated
## v2.0.3 - _September 25, 2018_
* Import SRA-related types from @0xproject/types (#1085)
## v2.0.2 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/connect",
"version": "2.0.2",
"version": "2.0.4",
"engines": {
"node": ">=6.12"
},
@@ -43,12 +43,12 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
"dependencies": {
"@0xproject/assert": "^1.0.9",
"@0xproject/json-schemas": "^1.0.2",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/assert": "^1.0.11",
"@0xproject/json-schemas": "^1.0.4",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"lodash": "^4.17.5",
"query-string": "^5.0.1",
"sinon": "^4.0.0",

View File

@@ -1,19 +1,10 @@
import { assert } from '@0xproject/assert';
import { schemas } from '@0xproject/json-schemas';
import { SignedOrder } from '@0xproject/types';
import { fetchAsync } from '@0xproject/utils';
import * as _ from 'lodash';
import * as queryString from 'query-string';
import { schemas as clientSchemas } from './schemas/schemas';
import {
APIOrder,
AssetPairsRequestOpts,
AssetPairsResponse,
Client,
FeeRecipientsResponse,
HttpRequestOptions,
HttpRequestType,
OrderbookRequest,
OrderbookResponse,
OrderConfigRequest,
@@ -22,14 +13,21 @@ import {
OrdersResponse,
PagedRequestOpts,
RequestOpts,
} from './types';
SignedOrder,
} from '@0xproject/types';
import { fetchAsync } from '@0xproject/utils';
import * as _ from 'lodash';
import * as queryString from 'query-string';
import { schemas as clientSchemas } from './schemas/schemas';
import { Client, HttpRequestOptions, HttpRequestType } from './types';
import { relayerResponseJsonParsers } from './utils/relayer_response_json_parsers';
const TRAILING_SLASHES_REGEX = /\/+$/;
/**
* This class includes all the functionality related to interacting with a set of HTTP endpoints
* that implement the standard relayer API v0
* that implement the standard relayer API v2
*/
export class HttpClient implements Client {
private readonly _apiEndpointUrl: string;

View File

@@ -1,23 +1,20 @@
export { HttpClient } from './http_client';
export { ordersChannelFactory } from './orders_channel_factory';
export { Client, OrdersChannel, OrdersChannelHandler } from './types';
export {
Client,
OrderConfigRequest,
OrderConfigResponse,
OrdersChannel,
OrdersChannelHandler,
OrdersChannelSubscriptionOpts,
OrderbookRequest,
OrderbookResponse,
OrdersRequestOpts,
PagedRequestOpts,
APIOrder,
AssetPairsRequestOpts,
RequestOpts,
AssetPairsResponse,
FeeRecipientsResponse,
APIOrder,
OrderbookRequest,
OrderbookResponse,
OrderConfigRequest,
OrderConfigResponse,
OrdersChannelSubscriptionOpts,
OrdersRequestOpts,
OrdersResponse,
PagedRequestOpts,
PaginatedCollection,
} from './types';
export { SignedOrder } from '@0xproject/types';
RequestOpts,
SignedOrder,
} from '@0xproject/types';

View File

@@ -1,5 +1,18 @@
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import {
APIOrder,
AssetPairsItem,
AssetPairsRequestOpts,
FeeRecipientsResponse,
OrderbookRequest,
OrderbookResponse,
OrderConfigRequest,
OrderConfigResponse,
OrdersChannelSubscriptionOpts,
OrdersRequestOpts,
PagedRequestOpts,
PaginatedCollection,
SignedOrder,
} from '@0xproject/types';
export interface Client {
getAssetPairsAsync: (
@@ -18,140 +31,12 @@ export interface OrdersChannel {
close: () => void;
}
/**
* baseAssetData: The address of assetData designated as the baseToken in the currency pair calculation of price
* quoteAssetData: The address of assetData designated as the quoteToken in the currency pair calculation of price
* limit: Maximum number of bids and asks in orderbook snapshot
*/
export interface OrdersChannelSubscriptionOpts {
baseAssetData: string;
quoteAssetData: string;
limit: number;
}
export interface OrdersChannelHandler {
onUpdate: (channel: OrdersChannel, subscriptionOpts: OrdersChannelSubscriptionOpts, orders: APIOrder[]) => void;
onError: (channel: OrdersChannel, err: Error, subscriptionOpts?: OrdersChannelSubscriptionOpts) => void;
onClose: (channel: OrdersChannel) => void;
}
export type OrdersChannelMessage = UpdateOrdersChannelMessage | UnknownOrdersChannelMessage;
export enum OrdersChannelMessageTypes {
Update = 'update',
Unknown = 'unknown',
}
export interface UpdateOrdersChannelMessage {
type: OrdersChannelMessageTypes.Update;
requestId: string;
payload: APIOrder[];
}
export interface UnknownOrdersChannelMessage {
type: OrdersChannelMessageTypes.Unknown;
requestId: string;
payload: undefined;
}
export enum WebsocketConnectionEventType {
Close = 'close',
Error = 'error',
Message = 'message',
}
export enum WebsocketClientEventType {
Connect = 'connect',
ConnectFailed = 'connectFailed',
}
export type OrdersResponse = PaginatedCollection<APIOrder>;
export interface APIOrder {
order: SignedOrder;
metaData: object;
}
export interface AssetPairsRequestOpts {
assetDataA?: string;
assetDataB?: string;
}
export type AssetPairsResponse = PaginatedCollection<AssetPairsItem>;
export interface AssetPairsItem {
assetDataA: Asset;
assetDataB: Asset;
}
export interface Asset {
assetData: string;
minAmount: BigNumber;
maxAmount: BigNumber;
precision: number;
}
export interface OrdersRequestOpts {
makerAssetProxyId?: string;
takerAssetProxyId?: string;
makerAssetAddress?: string;
takerAssetAddress?: string;
exchangeAddress?: string;
senderAddress?: string;
makerAssetData?: string;
takerAssetData?: string;
makerAddress?: string;
takerAddress?: string;
traderAddress?: string;
feeRecipientAddress?: string;
}
export interface OrderbookRequest {
baseAssetData: string;
quoteAssetData: string;
}
export interface OrderbookResponse {
bids: PaginatedCollection<APIOrder>;
asks: PaginatedCollection<APIOrder>;
}
export interface PaginatedCollection<T> {
total: number;
page: number;
perPage: number;
records: T[];
}
export interface OrderConfigRequest {
makerAddress: string;
takerAddress: string;
makerAssetAmount: BigNumber;
takerAssetAmount: BigNumber;
makerAssetData: string;
takerAssetData: string;
exchangeAddress: string;
expirationTimeSeconds: BigNumber;
}
export interface OrderConfigResponse {
makerFee: BigNumber;
takerFee: BigNumber;
feeRecipientAddress: string;
senderAddress: string;
}
export type FeeRecipientsResponse = PaginatedCollection<string>;
export interface RequestOpts {
networkId?: number;
}
export interface PagedRequestOpts {
page?: number;
perPage?: number;
}
export interface HttpRequestOptions {
params?: object;
payload?: object;

View File

@@ -2,7 +2,7 @@ import { assert } from '@0xproject/assert';
import { schemas } from '@0xproject/json-schemas';
import * as _ from 'lodash';
import { OrdersChannelMessage, OrdersChannelMessageTypes } from '../types';
import { OrdersChannelMessage, OrdersChannelMessageTypes } from '@0xproject/types';
import { relayerResponseJsonParsers } from './relayer_response_json_parsers';

View File

@@ -9,7 +9,7 @@ import {
OrderbookResponse,
OrderConfigResponse,
OrdersResponse,
} from '../types';
} from '@0xproject/types';
import { typeConverters } from './type_converters';

View File

@@ -1,7 +1,7 @@
import { orderParsingUtils } from '@0xproject/order-utils';
import * as _ from 'lodash';
import { APIOrder } from '../types';
import { APIOrder } from '@0xproject/types';
export const typeConverters = {
convertOrderbookStringFieldsToBigNumber(orderbook: any): any {

View File

@@ -1,8 +1,9 @@
import { OrdersChannelMessageTypes, OrdersChannelSubscriptionOpts } from '@0xproject/types';
import * as _ from 'lodash';
import { v4 as uuid } from 'uuid';
import * as WebSocket from 'websocket';
import { OrdersChannel, OrdersChannelHandler, OrdersChannelMessageTypes, OrdersChannelSubscriptionOpts } from './types';
import { OrdersChannel, OrdersChannelHandler } from './types';
import { assert } from './utils/assert';
import { ordersChannelMessageParser } from './utils/orders_channel_message_parser';

View File

@@ -1,6 +1,6 @@
import { BigNumber } from '@0xproject/utils';
import { AssetPairsResponse } from '../../../src/types';
import { AssetPairsResponse } from '@0xproject/types';
export const assetDataPairsResponse: AssetPairsResponse = {
total: 43,

View File

@@ -1,4 +1,4 @@
import { FeeRecipientsResponse } from '../../../src/types';
import { FeeRecipientsResponse } from '@0xproject/types';
export const feeRecipientsResponse: FeeRecipientsResponse = {
total: 3,

View File

@@ -1,6 +1,6 @@
import { BigNumber } from '@0xproject/utils';
import { OrderConfigResponse } from '../../../src/types';
import { OrderConfigResponse } from '@0xproject/types';
export const orderConfigResponse: OrderConfigResponse = {
senderAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',

View File

@@ -1,6 +1,6 @@
import { BigNumber } from '@0xproject/utils';
import { OrderbookResponse } from '../../../src/types';
import { OrderbookResponse } from '@0xproject/types';
export const orderbookResponse: OrderbookResponse = {
bids: {

View File

@@ -1,6 +1,6 @@
import { BigNumber } from '@0xproject/utils';
import { OrdersResponse } from '../../../src/types';
import { OrdersResponse } from '@0xproject/types';
export const ordersResponse: OrdersResponse = {
total: 984,

View File

@@ -1,12 +1,37 @@
[
{
"timestamp": 1537541580,
"version": "2.0.0",
"changes": [
{
"note":
"Fixes dropped events in subscriptions by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too.",
"pr": 1080
},
{
"note":
"Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it",
"pr": 1080
}
],
"timestamp": 1537907159
},
{
"version": "1.0.5",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1537875740
},
{
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
],
"timestamp": 1537541580
},
{
"version": "1.0.3",

View File

@@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.0 - _September 25, 2018_
* Fixes dropped events in subscriptions by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too. (#1080)
* Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it (#1080)
## v1.0.5 - _September 25, 2018_
* Dependencies updated
## v1.0.4 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/contract-wrappers",
"version": "1.0.4",
"version": "2.0.0",
"description": "Smart TS wrappers for 0x smart contracts",
"keywords": [
"0xproject",
@@ -41,10 +41,10 @@
"node": ">=6.0.0"
},
"devDependencies": {
"@0xproject/abi-gen": "^1.0.9",
"@0xproject/dev-utils": "^1.0.8",
"@0xproject/migrations": "^1.0.10",
"@0xproject/subproviders": "^2.0.3",
"@0xproject/abi-gen": "^1.0.11",
"@0xproject/dev-utils": "^1.0.10",
"@0xproject/migrations": "^1.0.12",
"@0xproject/subproviders": "^2.0.5",
"@0xproject/tslint-config": "^1.0.7",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
@@ -72,17 +72,17 @@
"web3-provider-engine": "14.0.6"
},
"dependencies": {
"@0xproject/assert": "^1.0.9",
"@0xproject/base-contract": "^2.0.3",
"@0xproject/fill-scenarios": "^1.0.3",
"@0xproject/json-schemas": "^1.0.2",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"ethereum-types": "^1.0.7",
"ethereumjs-blockstream": "5.0.0",
"@0xproject/assert": "^1.0.11",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/fill-scenarios": "^1.0.5",
"@0xproject/json-schemas": "^1.0.4",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"ethereum-types": "^1.0.8",
"ethereumjs-blockstream": "6.0.0",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
"js-sha3": "^0.7.0",

View File

@@ -1,5 +1,5 @@
import { AbiDecoder, intervalUtils, logUtils } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { marshaller, Web3Wrapper } from '@0xproject/web3-wrapper';
import {
BlockParamLiteral,
ContractAbi,
@@ -8,6 +8,7 @@ import {
LogEntry,
LogWithDecodedArgs,
RawLog,
RawLogEntry,
} from 'ethereum-types';
import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream';
import * as _ from 'lodash';
@@ -157,7 +158,8 @@ export abstract class ContractWrapper {
return addressIfExists;
}
}
private _onLogStateChanged<ArgsType extends ContractEventArgs>(isRemoved: boolean, log: LogEntry): void {
private _onLogStateChanged<ArgsType extends ContractEventArgs>(isRemoved: boolean, rawLog: RawLogEntry): void {
const log: LogEntry = marshaller.unmarshalLog(rawLog);
_.forEach(this._filters, (filter: FilterObject, filterToken: string) => {
if (filterUtils.matchesFilter(log, filter)) {
const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs<ArgsType>;
@@ -174,8 +176,8 @@ export abstract class ContractWrapper {
throw new Error(ContractWrappersError.SubscriptionAlreadyPresent);
}
this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
this._blockstreamGetBlockOrNullAsync.bind(this),
this._blockstreamGetLogsAsync.bind(this),
ContractWrapper._onBlockAndLogStreamerError.bind(this, isVerbose),
);
const catchAllLogFilter = {};
@@ -194,6 +196,32 @@ export abstract class ContractWrapper {
this._onLogStateChanged.bind(this, isRemoved),
);
}
// This method only exists in order to comply with the expected interface of Blockstream's constructor
private async _blockstreamGetBlockOrNullAsync(hash: string): Promise<Block | null> {
const shouldIncludeTransactionData = false;
const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync<Block | null>({
method: 'eth_getBlockByHash',
params: [hash, shouldIncludeTransactionData],
});
return blockOrNull;
}
// This method only exists in order to comply with the expected interface of Blockstream's constructor
private async _blockstreamGetLatestBlockOrNullAsync(): Promise<Block | null> {
const shouldIncludeTransactionData = false;
const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync<Block | null>({
method: 'eth_getBlockByNumber',
params: [BlockParamLiteral.Latest, shouldIncludeTransactionData],
});
return blockOrNull;
}
// This method only exists in order to comply with the expected interface of Blockstream's constructor
private async _blockstreamGetLogsAsync(filterOptions: FilterObject): Promise<RawLogEntry[]> {
const logs = await this._web3Wrapper.sendRawPayloadAsync<RawLogEntry[]>({
method: 'eth_getLogs',
params: [filterOptions],
});
return logs as RawLogEntry[];
}
// HACK: This should be a package-scoped method (which doesn't exist in TS)
// We don't want this method available in the public interface for all classes
// who inherit from ContractWrapper, and it is only used by the internal implementation
@@ -212,11 +240,14 @@ export abstract class ContractWrapper {
delete this._blockAndLogStreamerIfExists;
}
private async _reconcileBlockAsync(): Promise<void> {
const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest);
const latestBlockOrNull = await this._blockstreamGetLatestBlockOrNullAsync();
if (_.isNull(latestBlockOrNull)) {
return; // noop
}
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlockOrNull);
}
}
}

View File

@@ -12,6 +12,7 @@ import { TransactionOpts } from '../types';
import { assert } from '../utils/assert';
import { calldataOptimizationUtils } from '../utils/calldata_optimization_utils';
import { constants } from '../utils/constants';
import { utils } from '../utils/utils';
import { ContractWrapper } from './contract_wrapper';
import { ForwarderContract } from './generated/forwarder';
@@ -57,7 +58,7 @@ export class ForwarderWrapper extends ContractWrapper {
takerAddress: string,
ethAmount: BigNumber,
signedFeeOrders: SignedOrder[] = [],
feePercentage: BigNumber = constants.ZERO_AMOUNT,
feePercentage: number = 0,
feeRecipientAddress: string = constants.NULL_ADDRESS,
txOpts: TransactionOpts = {},
): Promise<string> {
@@ -66,7 +67,7 @@ export class ForwarderWrapper extends ContractWrapper {
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
assert.isBigNumber('ethAmount', ethAmount);
assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
assert.isBigNumber('feePercentage', feePercentage);
assert.isNumber('feePercentage', feePercentage);
assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
// other assertions
@@ -76,6 +77,8 @@ export class ForwarderWrapper extends ContractWrapper {
this.getZRXTokenAddress(),
this.getEtherTokenAddress(),
);
// format feePercentage
const formattedFeePercentage = utils.numberPercentageToEtherTokenAmountPercentage(feePercentage);
// lowercase input addresses
const normalizedTakerAddress = takerAddress.toLowerCase();
const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
@@ -89,7 +92,7 @@ export class ForwarderWrapper extends ContractWrapper {
_.map(optimizedMarketOrders, order => order.signature),
optimizedFeeOrders,
_.map(optimizedFeeOrders, order => order.signature),
feePercentage,
formattedFeePercentage,
feeRecipientAddress,
{
value: ethAmount,
@@ -124,7 +127,7 @@ export class ForwarderWrapper extends ContractWrapper {
takerAddress: string,
ethAmount: BigNumber,
signedFeeOrders: SignedOrder[] = [],
feePercentage: BigNumber = constants.ZERO_AMOUNT,
feePercentage: number = 0,
feeRecipientAddress: string = constants.NULL_ADDRESS,
txOpts: TransactionOpts = {},
): Promise<string> {
@@ -134,7 +137,7 @@ export class ForwarderWrapper extends ContractWrapper {
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
assert.isBigNumber('ethAmount', ethAmount);
assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
assert.isBigNumber('feePercentage', feePercentage);
assert.isNumber('feePercentage', feePercentage);
assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
// other assertions
@@ -144,6 +147,8 @@ export class ForwarderWrapper extends ContractWrapper {
this.getZRXTokenAddress(),
this.getEtherTokenAddress(),
);
// format feePercentage
const formattedFeePercentage = utils.numberPercentageToEtherTokenAmountPercentage(feePercentage);
// lowercase input addresses
const normalizedTakerAddress = takerAddress.toLowerCase();
const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
@@ -158,7 +163,7 @@ export class ForwarderWrapper extends ContractWrapper {
_.map(optimizedMarketOrders, order => order.signature),
optimizedFeeOrders,
_.map(optimizedFeeOrders, order => order.signature),
feePercentage,
formattedFeePercentage,
feeRecipientAddress,
{
value: ethAmount,

View File

@@ -12,4 +12,6 @@ export const constants = {
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
ZERO_AMOUNT: new BigNumber(0),
ONE_AMOUNT: new BigNumber(1),
ETHER_TOKEN_DECIMALS: 18,
};

View File

@@ -1,4 +1,7 @@
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { constants } from './constants';
export const utils = {
getCurrentUnixTimestampSec(): BigNumber {
@@ -8,4 +11,7 @@ export const utils = {
getCurrentUnixTimestampMs(): BigNumber {
return new BigNumber(Date.now());
},
numberPercentageToEtherTokenAmountPercentage(percentage: number): BigNumber {
return Web3Wrapper.toBaseUnitAmount(constants.ONE_AMOUNT, constants.ETHER_TOKEN_DECIMALS).mul(percentage);
},
};

View File

@@ -61,7 +61,7 @@ describe('SubscriptionTest', () => {
callback,
);
stubs = [
Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockAsync').throws(
Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockIfExistsAsync').throws(
new Error('JSON RPC error'),
),
];

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "contracts",
"version": "2.1.45",
"version": "2.1.47",
"engines": {
"node": ">=6.12"
},
@@ -45,11 +45,11 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
"devDependencies": {
"@0xproject/abi-gen": "^1.0.9",
"@0xproject/dev-utils": "^1.0.8",
"@0xproject/sol-compiler": "^1.1.3",
"@0xproject/sol-cov": "^2.1.3",
"@0xproject/subproviders": "^2.0.3",
"@0xproject/abi-gen": "^1.0.11",
"@0xproject/dev-utils": "^1.0.10",
"@0xproject/sol-compiler": "^1.1.5",
"@0xproject/sol-cov": "^2.1.5",
"@0xproject/subproviders": "^2.0.5",
"@0xproject/tslint-config": "^1.0.7",
"@types/bn.js": "^4.11.0",
"@types/ethereumjs-abi": "^0.6.0",
@@ -72,15 +72,15 @@
"yargs": "^10.0.3"
},
"dependencies": {
"@0xproject/base-contract": "^2.0.3",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"@types/js-combinatorics": "^0.5.29",
"bn.js": "^4.11.8",
"ethereum-types": "^1.0.7",
"ethereum-types": "^1.0.8",
"ethereumjs-abi": "0.6.5",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",

View File

@@ -269,7 +269,10 @@ describe('MultiSigWalletWithTimeLock', () => {
expect(confirmRes.logs).to.have.length(2);
const blockNum = await web3Wrapper.getBlockNumberAsync();
const blockInfo = await web3Wrapper.getBlockAsync(blockNum);
const blockInfo = await web3Wrapper.getBlockIfExistsAsync(blockNum);
if (_.isUndefined(blockInfo)) {
throw new Error(`Unexpectedly failed to fetch block at #${blockNum}`);
}
const timestamp = new BigNumber(blockInfo.timestamp);
const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes.callAsync(txId));

View File

@@ -35,6 +35,9 @@ export async function increaseTimeAndMineBlockAsync(seconds: number): Promise<nu
* @returns a new Promise which will resolve with the timestamp in seconds.
*/
export async function getLatestBlockTimestampAsync(): Promise<number> {
const currentBlock = await web3Wrapper.getBlockAsync('latest');
return currentBlock.timestamp;
const currentBlockIfExists = await web3Wrapper.getBlockIfExistsAsync('latest');
if (_.isUndefined(currentBlockIfExists)) {
throw new Error(`Unable to fetch latest block.`);
}
return currentBlockIfExists.timestamp;
}

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1537907159,
"version": "1.0.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "1.0.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "1.0.8",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.10 - _September 25, 2018_
* Dependencies updated
## v1.0.9 - _September 25, 2018_
* Dependencies updated
## v1.0.8 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/dev-utils",
"version": "1.0.8",
"version": "1.0.10",
"engines": {
"node": ">=6.12"
},
@@ -42,12 +42,12 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0xproject/subproviders": "^2.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"ethereum-types": "^1.0.7",
"@0xproject/subproviders": "^2.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"ethereum-types": "^1.0.8",
"lodash": "^4.17.5"
},
"publishConfig": {

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1537907159,
"version": "1.0.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "1.0.7",

View File

@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.8 - _September 25, 2018_
* Dependencies updated
## v1.0.7 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "ethereum-types",
"version": "1.0.7",
"version": "1.0.8",
"engines": {
"node": ">=6.12"
},

View File

@@ -181,6 +181,7 @@ export interface CallData extends CallTxDataBase {
export interface FilterObject {
fromBlock?: number | string;
toBlock?: number | string;
blockHash?: string;
address?: string;
topics?: LogTopic[];
}

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.5 - _September 25, 2018_
* Dependencies updated
## v1.0.4 - _September 25, 2018_
* Dependencies updated
## v1.0.3 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/fill-scenarios",
"version": "1.0.3",
"version": "1.0.5",
"description": "0x order fill scenario generator",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@@ -26,7 +26,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md",
"devDependencies": {
"@0xproject/abi-gen": "^1.0.9",
"@0xproject/abi-gen": "^1.0.11",
"@0xproject/tslint-config": "^1.0.7",
"@types/lodash": "4.14.104",
"copyfiles": "^2.0.0",
@@ -37,13 +37,13 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0xproject/base-contract": "^2.0.3",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"ethereum-types": "^1.0.7",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"ethereum-types": "^1.0.8",
"ethers": "3.0.22",
"lodash": "^4.17.5"
},

View File

@@ -1,57 +0,0 @@
[
{
"timestamp": 1537541580,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537369748,
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537265493,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1536142250,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.1-rc.2",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1535377027
},
{
"version": "1.0.1-rc.1",
"changes": [
{
"note": "Add initial forwarderHelperFactory",
"pr": 997
}
],
"timestamp": 1535133899
}
]

View File

@@ -1,30 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.4 - _September 21, 2018_
* Dependencies updated
## v1.0.3 - _September 19, 2018_
* Dependencies updated
## v1.0.2 - _September 18, 2018_
* Dependencies updated
## v1.0.1 - _September 5, 2018_
* Dependencies updated
## v1.0.1-rc.2 - _August 27, 2018_
* Dependencies updated
## v1.0.1-rc.1 - _August 24, 2018_
* Add initial forwarderHelperFactory (#997)

View File

@@ -1,83 +0,0 @@
## @0xproject/forwarder-helper
Provides convenience objects to help work with the Forwarder Contract
### Read the [Documentation](https://0xproject.com/docs/forwarder-helper).
## Installation
```bash
yarn add @0xproject/forwarder-helper
```
**Import**
```typescript
import { forwarderHelperFactory } from '@0xproject/forwarder-helper';
```
or
```javascript
var forwarderHelperFactory = require('@0xproject/forwarder-helper').forwarderHelperFactory;
```
If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`:
```json
"compilerOptions": {
"typeRoots": ["node_modules/@0xproject/typescript-typings/types", "node_modules/@types"],
}
```
## Contributing
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0xproject/forwarder-helper yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0xproject/forwarder-helper yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@@ -1,5 +0,0 @@
import { BigNumber } from '@0xproject/utils';
export const constants = {
ZERO_AMOUNT: new BigNumber(0),
};

View File

@@ -1,25 +0,0 @@
import { assert } from '@0xproject/assert';
import { schemas } from '@0xproject/json-schemas';
import { SignedOrder } from '@0xproject/types';
import { ForwarderHelperImpl, ForwarderHelperImplConfig } from './forwarder_helper_impl';
import { ForwarderHelper } from './types';
export const forwarderHelperFactory = {
/**
* Given an array of orders and an array of feeOrders
* @param orders An array of objects conforming to SignedOrder. Each order should specify the same makerAssetData and takerAssetData
* @param feeOrders An array of objects conforming to SignedOrder. Each order should specify ZRX as makerAssetData WETH as takerAssetData
* @return A ForwarderHelper, see type for definition
*/
getForwarderHelperForOrders(orders: SignedOrder[], feeOrders: SignedOrder[] = []): ForwarderHelper {
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
assert.doesConformToSchema('feeOrders', orders, schemas.signedOrdersSchema);
const config: ForwarderHelperImplConfig = {
orders,
feeOrders,
};
const helper = new ForwarderHelperImpl(config);
return helper;
},
};

View File

@@ -1,64 +0,0 @@
import { marketUtils } from '@0xproject/order-utils';
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import { constants } from './constants';
import { ForwarderHelper, ForwarderHelperError, MarketBuyOrdersInfo, MarketBuyOrdersInfoRequest } from './types';
import { forwarderHelperImplConfigUtils } from './utils/forwarder_helper_impl_config_utils';
const SLIPPAGE_PERCENTAGE = new BigNumber(0.2); // 20% slippage protection, possibly move this into request interface
export interface ForwarderHelperImplConfig {
orders: SignedOrder[];
feeOrders: SignedOrder[];
remainingFillableMakerAssetAmounts?: BigNumber[];
remainingFillableFeeAmounts?: BigNumber[];
}
export class ForwarderHelperImpl implements ForwarderHelper {
public readonly config: ForwarderHelperImplConfig;
constructor(config: ForwarderHelperImplConfig) {
this.config = forwarderHelperImplConfigUtils.sortedConfig(config);
}
public getMarketBuyOrdersInfo(request: MarketBuyOrdersInfoRequest): MarketBuyOrdersInfo {
const { makerAssetFillAmount, feePercentage } = request;
const { orders, feeOrders, remainingFillableMakerAssetAmounts, remainingFillableFeeAmounts } = this.config;
// TODO: make the slippage percentage customizable
const slippageBufferAmount = makerAssetFillAmount.mul(SLIPPAGE_PERCENTAGE).round();
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
orders,
makerAssetFillAmount,
{
remainingFillableMakerAssetAmounts,
slippageBufferAmount,
},
);
if (remainingFillAmount.gt(constants.ZERO_AMOUNT)) {
throw new Error(ForwarderHelperError.InsufficientMakerAssetLiquidity);
}
// TODO: update this logic to find the minimum amount of feeOrders to cover the worst case as opposed to
// finding order that cover all fees, this will help with estimating ETH and minimizing gas usage
const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
resultOrders,
feeOrders,
{
remainingFillableMakerAssetAmounts,
remainingFillableFeeAmounts,
},
);
if (remainingFeeAmount.gt(constants.ZERO_AMOUNT)) {
throw new Error(ForwarderHelperError.InsufficientZrxLiquidity);
}
// TODO: calculate min and max eth usage
// TODO: optimize orders call data
return {
makerAssetFillAmount,
orders: resultOrders,
feeOrders: resultFeeOrders,
minEthAmount: constants.ZERO_AMOUNT,
maxEthAmount: constants.ZERO_AMOUNT,
feePercentage,
};
}
}

View File

@@ -1,2 +0,0 @@
export { forwarderHelperFactory } from './forwarder_helper_factory';
export { ForwarderHelper, ForwarderHelperError, MarketBuyOrdersInfoRequest, MarketBuyOrdersInfo } from './types';

View File

@@ -1,43 +0,0 @@
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
export interface ForwarderHelper {
/**
* Given a MarketBuyOrdersInfoRequest, returns a MarketBuyOrdersInfo containing all information relevant to fulfilling the request
* using the ForwarderContract marketBuyOrdersWithEth function.
* @param request An object that conforms to MarketBuyOrdersInfoRequest. See type definition for more information.
* @return An object that conforms to MarketBuyOrdersInfo that satisfies the request. See type definition for more information.
*/
getMarketBuyOrdersInfo: (request: MarketBuyOrdersInfoRequest) => MarketBuyOrdersInfo;
}
export enum ForwarderHelperError {
InsufficientMakerAssetLiquidity = 'INSUFFICIENT_MAKER_ASSET_LIQUIDITY',
InsufficientZrxLiquidity = 'INSUFFICIENT_ZRX_LIQUIDITY',
}
/**
* makerAssetFillAmount: The amount of makerAsset requesting to be filled
* feePercentage: Optional affiliate percentage amount factoring into eth amount calculations
*/
export interface MarketBuyOrdersInfoRequest {
makerAssetFillAmount: BigNumber;
feePercentage?: BigNumber;
}
/**
* makerAssetFillAmount: The amount of makerAsset requesting to be filled
* orders: An array of objects conforming to SignedOrder. These orders can be used to cover the requested makerAssetFillAmount plus slippage
* feeOrders: An array of objects conforming to SignedOrder. These orders can be used to cover the fees for the orders param above
* minEthAmount: Amount of eth in wei to send with the tx for the most optimistic case
* maxEthAmount: Amount of eth in wei to send with the tx for the worst case
* feePercentage: Affiliate fee percentage used to calculate the eth amounts above. Passed thru directly from the request
*/
export interface MarketBuyOrdersInfo {
makerAssetFillAmount: BigNumber;
orders: SignedOrder[];
feeOrders: SignedOrder[];
minEthAmount: BigNumber;
maxEthAmount: BigNumber;
feePercentage?: BigNumber;
}

View File

@@ -1,92 +0,0 @@
import { sortingUtils } from '@0xproject/order-utils';
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import { ForwarderHelperImplConfig } from '../forwarder_helper_impl';
interface SignedOrderWithAmount extends SignedOrder {
remainingFillAmount: BigNumber;
}
export const forwarderHelperImplConfigUtils = {
sortedConfig(config: ForwarderHelperImplConfig): ForwarderHelperImplConfig {
const { orders, feeOrders, remainingFillableMakerAssetAmounts, remainingFillableFeeAmounts } = config;
// TODO: provide a feeRate to the sorting function to more accurately sort based on the current market for ZRX tokens
const orderSorter = (ordersToSort: SignedOrder[]) => {
return sortingUtils.sortOrdersByFeeAdjustedRate(ordersToSort);
};
const sortOrdersResult = sortOrdersAndRemainingFillAmounts(
orderSorter,
orders,
remainingFillableMakerAssetAmounts,
);
const feeOrderSorter = (ordersToSort: SignedOrder[]) => {
return sortingUtils.sortFeeOrdersByFeeAdjustedRate(ordersToSort);
};
const sortFeeOrdersResult = sortOrdersAndRemainingFillAmounts(
feeOrderSorter,
feeOrders,
remainingFillableFeeAmounts,
);
return {
orders: sortOrdersResult.orders,
feeOrders: sortFeeOrdersResult.orders,
remainingFillableMakerAssetAmounts: sortOrdersResult.remainingFillAmounts,
remainingFillableFeeAmounts: sortFeeOrdersResult.remainingFillAmounts,
};
},
};
type OrderSorter = (orders: SignedOrder[]) => SignedOrder[];
function sortOrdersAndRemainingFillAmounts(
orderSorter: OrderSorter,
orders: SignedOrder[],
remainingFillAmounts?: BigNumber[],
): { orders: SignedOrder[]; remainingFillAmounts?: BigNumber[] } {
if (!_.isUndefined(remainingFillAmounts)) {
// Bundle orders together with their remainingFillAmounts so that we can sort them together
const orderWithAmounts = bundleSignedOrderWithAmounts(orders, remainingFillAmounts);
// Sort
const sortedOrderWithAmounts = orderSorter(orderWithAmounts) as SignedOrderWithAmount[];
// Unbundle after sorting
const unbundledSortedOrderWithAmounts = unbundleSignedOrderWithAmounts(sortedOrderWithAmounts);
return {
orders: unbundledSortedOrderWithAmounts.orders,
remainingFillAmounts: unbundledSortedOrderWithAmounts.amounts,
};
} else {
const sortedOrders = orderSorter(orders);
return {
orders: sortedOrders,
};
}
}
function bundleSignedOrderWithAmounts(orders: SignedOrder[], amounts: BigNumber[]): SignedOrderWithAmount[] {
const ordersAndAmounts = _.map(orders, (order, index) => {
return {
...order,
remainingFillAmount: amounts[index],
};
});
return ordersAndAmounts;
}
function unbundleSignedOrderWithAmounts(
signedOrderWithAmounts: SignedOrderWithAmount[],
): { orders: SignedOrder[]; amounts: BigNumber[] } {
const orders = _.map(signedOrderWithAmounts, order => {
const { remainingFillAmount, ...rest } = order;
return rest;
});
const amounts = _.map(signedOrderWithAmounts, order => {
const { remainingFillAmount } = order;
return remainingFillAmount;
});
return {
orders,
amounts,
};
}

View File

@@ -1,136 +0,0 @@
import { testOrderFactory } from '@0xproject/order-utils/lib/test/utils/test_order_factory';
import { BigNumber } from '@0xproject/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import { ForwarderHelperImpl, ForwarderHelperImplConfig } from '../src/forwarder_helper_impl';
import { ForwarderHelperError } from '../src/types';
import { chaiSetup } from './utils/chai_setup';
chaiSetup.configure();
const expect = chai.expect;
describe('ForwarderHelperImpl', () => {
// rate: 2 takerAsset / makerAsset
const testOrder1 = testOrderFactory.generateTestSignedOrder({
makerAssetAmount: new BigNumber(100),
takerAssetAmount: new BigNumber(200),
});
// rate: 1 takerAsset / makerAsset
const testOrder2 = testOrderFactory.generateTestSignedOrder({
makerAssetAmount: new BigNumber(100),
takerAssetAmount: new BigNumber(100),
});
// rate: 3 takerAsset / makerAsset
const testOrder3 = testOrderFactory.generateTestSignedOrder({
makerAssetAmount: new BigNumber(100),
takerAssetAmount: new BigNumber(300),
takerFee: new BigNumber(1),
});
// rate: 3 WETH / ZRX
const testFeeOrder1 = testOrderFactory.generateTestSignedOrder({
makerAssetAmount: new BigNumber(100),
takerAssetAmount: new BigNumber(300),
});
// rate: 2 WETH / ZRX
const testFeeOrder2 = testOrderFactory.generateTestSignedOrder({
makerAssetAmount: new BigNumber(100),
takerAssetAmount: new BigNumber(200),
});
// rate: 1 WETH / ZRX
const testFeeOrder3 = testOrderFactory.generateTestSignedOrder({
makerAssetAmount: new BigNumber(100),
takerAssetAmount: new BigNumber(100),
});
const inputForwarderHelperConfig: ForwarderHelperImplConfig = {
orders: [testOrder1, testOrder2, testOrder3],
feeOrders: [testFeeOrder1, testFeeOrder2, testFeeOrder3],
remainingFillableMakerAssetAmounts: [new BigNumber(1), new BigNumber(2), new BigNumber(3)],
remainingFillableFeeAmounts: [new BigNumber(4), new BigNumber(5), new BigNumber(6)],
};
describe('#constructor', () => {
const inputForwarderHelperConfigNoRemainingAmounts: ForwarderHelperImplConfig = {
orders: [testOrder1, testOrder2, testOrder3],
feeOrders: [testFeeOrder1, testFeeOrder2, testFeeOrder3],
};
it('sorts orders', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfig);
expect(forwarderHelper.config.orders).deep.equals([testOrder2, testOrder1, testOrder3]);
});
it('sorts fee orders', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfig);
expect(forwarderHelper.config.feeOrders).deep.equals([testFeeOrder3, testFeeOrder2, testFeeOrder1]);
});
it('sorts remainingFillableMakerAssetAmounts', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfig);
expect(forwarderHelper.config.remainingFillableMakerAssetAmounts).to.be.not.undefined();
expect(_.nth(forwarderHelper.config.remainingFillableMakerAssetAmounts, 0)).to.bignumber.equal(
new BigNumber(2),
);
expect(_.nth(forwarderHelper.config.remainingFillableMakerAssetAmounts, 1)).to.bignumber.equal(
new BigNumber(1),
);
expect(_.nth(forwarderHelper.config.remainingFillableMakerAssetAmounts, 2)).to.bignumber.equal(
new BigNumber(3),
);
});
it('sorts remainingFillableFeeAmounts', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfig);
expect(forwarderHelper.config.remainingFillableFeeAmounts).to.be.not.undefined();
expect(_.nth(forwarderHelper.config.remainingFillableFeeAmounts, 0)).to.bignumber.equal(new BigNumber(6));
expect(_.nth(forwarderHelper.config.remainingFillableFeeAmounts, 1)).to.bignumber.equal(new BigNumber(5));
expect(_.nth(forwarderHelper.config.remainingFillableFeeAmounts, 2)).to.bignumber.equal(new BigNumber(4));
});
it('remainingFillableMakerAssetAmounts is undefined if none provided', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfigNoRemainingAmounts);
expect(forwarderHelper.config.remainingFillableMakerAssetAmounts).to.be.undefined();
});
it('remainingFillableFeeAmounts is undefined if none provided', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfigNoRemainingAmounts);
expect(forwarderHelper.config.remainingFillableFeeAmounts).to.be.undefined();
});
});
describe('#getMarketBuyOrdersInfo', () => {
it('throws if not enough makerAsset liquidity', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfig);
expect(() => {
// request for 6 makerAsset units, because we have exactly 6 available we should throw because there is a built in slippage buffer
forwarderHelper.getMarketBuyOrdersInfo({
makerAssetFillAmount: new BigNumber(6),
});
}).to.throw(ForwarderHelperError.InsufficientMakerAssetLiquidity);
});
it('throws if not enough ZRX liquidity', () => {
const inputForwarderHelperConfigNoFees: ForwarderHelperImplConfig = {
orders: [testOrder1, testOrder2, testOrder3],
feeOrders: [],
};
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfigNoFees);
expect(() => {
// request for 4 makerAsset units, we need fees but no fee orders exist, show we should throw
forwarderHelper.getMarketBuyOrdersInfo({
makerAssetFillAmount: new BigNumber(250),
});
}).to.throw(ForwarderHelperError.InsufficientZrxLiquidity);
});
it('passes the makerAssetFillAmount from the request to the info response', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfig);
const makerAssetFillAmount = new BigNumber(4);
const info = forwarderHelper.getMarketBuyOrdersInfo({
makerAssetFillAmount,
});
expect(info.makerAssetFillAmount).to.bignumber.equal(makerAssetFillAmount);
});
it('passes the feePercentage from the request to the info response', () => {
const forwarderHelper = new ForwarderHelperImpl(inputForwarderHelperConfig);
const feePercentage = new BigNumber(0.2);
const info = forwarderHelper.getMarketBuyOrdersInfo({
makerAssetFillAmount: new BigNumber(4),
feePercentage,
});
expect(info.feePercentage).to.bignumber.equal(feePercentage);
});
});
});

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1537907159,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "1.0.2",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.4 - _September 25, 2018_
* Dependencies updated
## v1.0.3 - _September 25, 2018_
* Dependencies updated
## v1.0.2 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/json-schemas",
"version": "1.0.2",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
@@ -38,14 +38,14 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/json-schemas/README.md",
"dependencies": {
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/typescript-typings": "^2.0.2",
"@types/node": "*",
"jsonschema": "^1.2.0",
"lodash.values": "^4.3.0"
},
"devDependencies": {
"@0xproject/tslint-config": "^1.0.7",
"@0xproject/utils": "^1.0.9",
"@0xproject/utils": "^1.0.11",
"@types/lodash.foreach": "^4.5.3",
"@types/lodash.values": "^4.3.3",
"@types/mocha": "^2.2.42",

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/metacoin",
"version": "0.0.19",
"version": "0.0.21",
"engines": {
"node": ">=6.12"
},
@@ -28,25 +28,25 @@
"author": "",
"license": "Apache-2.0",
"dependencies": {
"@0xproject/abi-gen": "^1.0.9",
"@0xproject/base-contract": "^2.0.3",
"@0xproject/sol-cov": "^2.1.3",
"@0xproject/subproviders": "^2.0.3",
"@0xproject/abi-gen": "^1.0.11",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/sol-cov": "^2.1.5",
"@0xproject/subproviders": "^2.0.5",
"@0xproject/tslint-config": "^1.0.7",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"@types/mocha": "^5.2.2",
"copyfiles": "^2.0.0",
"ethereum-types": "^1.0.7",
"ethereum-types": "^1.0.8",
"ethers": "3.0.22",
"lodash": "^4.17.5",
"run-s": "^0.0.0"
},
"devDependencies": {
"@0xproject/dev-utils": "^1.0.8",
"@0xproject/sol-compiler": "^1.1.3",
"@0xproject/dev-utils": "^1.0.10",
"@0xproject/sol-compiler": "^1.1.5",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",

1
packages/migrations/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
artifacts/development

View File

@@ -1,4 +1,22 @@
[
{
"timestamp": 1537907159,
"version": "1.0.12",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537875740,
"version": "1.0.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1537541580,
"version": "1.0.10",

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.12 - _September 25, 2018_
* Dependencies updated
## v1.0.11 - _September 25, 2018_
* Dependencies updated
## v1.0.10 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/migrations",
"version": "1.0.10",
"version": "1.0.12",
"engines": {
"node": ">=6.12"
},
@@ -30,10 +30,10 @@
},
"license": "Apache-2.0",
"devDependencies": {
"@0xproject/abi-gen": "^1.0.9",
"@0xproject/dev-utils": "^1.0.8",
"@0xproject/abi-gen": "^1.0.11",
"@0xproject/dev-utils": "^1.0.10",
"@0xproject/tslint-config": "^1.0.7",
"@0xproject/types": "^1.0.2",
"@0xproject/types": "^1.1.1",
"@types/yargs": "^10.0.0",
"copyfiles": "^2.0.0",
"make-promises-safe": "^1.1.0",
@@ -44,15 +44,15 @@
"yargs": "^10.0.3"
},
"dependencies": {
"@0xproject/base-contract": "^2.0.3",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/sol-compiler": "^1.1.3",
"@0xproject/subproviders": "^2.0.3",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/sol-compiler": "^1.1.5",
"@0xproject/subproviders": "^2.0.5",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"@ledgerhq/hw-app-eth": "^4.3.0",
"ethereum-types": "^1.0.7",
"ethereum-types": "^1.0.8",
"ethers": "3.0.22",
"lodash": "^4.17.5"
},

View File

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

View File

@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.5 - _September 25, 2018_
* Dependencies updated
## v1.0.4 - _September 25, 2018_
* Dependencies updated
## v1.0.3 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/order-utils",
"version": "1.0.3",
"version": "1.0.5",
"engines": {
"node": ">=6.12"
},
@@ -38,7 +38,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md",
"devDependencies": {
"@0xproject/dev-utils": "^1.0.8",
"@0xproject/dev-utils": "^1.0.10",
"@0xproject/tslint-config": "^1.0.7",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
@@ -57,16 +57,16 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0xproject/assert": "^1.0.9",
"@0xproject/base-contract": "^2.0.3",
"@0xproject/json-schemas": "^1.0.2",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"@0xproject/assert": "^1.0.11",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/json-schemas": "^1.0.4",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"@types/node": "*",
"bn.js": "^4.11.8",
"ethereum-types": "^1.0.7",
"ethereum-types": "^1.0.8",
"ethereumjs-abi": "0.6.5",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",

View File

@@ -51,17 +51,23 @@ export const marketUtils = {
// iterate through the orders input from left to right until we have enough makerAsset to fill totalFillAmount
const result = _.reduce(
orders,
({ resultOrders, remainingFillAmount }, order, index) => {
({ resultOrders, remainingFillAmount, ordersRemainingFillableMakerAssetAmounts }, order, index) => {
if (remainingFillAmount.lessThanOrEqualTo(constants.ZERO_AMOUNT)) {
return { resultOrders, remainingFillAmount: constants.ZERO_AMOUNT };
return {
resultOrders,
remainingFillAmount: constants.ZERO_AMOUNT,
ordersRemainingFillableMakerAssetAmounts,
};
} else {
const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index];
const shouldIncludeOrder = makerAssetAmountAvailable.gt(constants.ZERO_AMOUNT);
// if there is no makerAssetAmountAvailable do not append order to resultOrders
// if we have exceeded the total amount we want to fill set remainingFillAmount to 0
return {
resultOrders: makerAssetAmountAvailable.gt(constants.ZERO_AMOUNT)
? _.concat(resultOrders, order)
: resultOrders,
resultOrders: shouldIncludeOrder ? _.concat(resultOrders, order) : resultOrders,
ordersRemainingFillableMakerAssetAmounts: shouldIncludeOrder
? _.concat(ordersRemainingFillableMakerAssetAmounts, makerAssetAmountAvailable)
: ordersRemainingFillableMakerAssetAmounts,
remainingFillAmount: BigNumber.max(
constants.ZERO_AMOUNT,
remainingFillAmount.minus(makerAssetAmountAvailable),
@@ -69,7 +75,11 @@ export const marketUtils = {
};
}
},
{ resultOrders: [] as T[], remainingFillAmount: totalFillAmount },
{
resultOrders: [] as T[],
remainingFillAmount: totalFillAmount,
ordersRemainingFillableMakerAssetAmounts: [] as BigNumber[],
},
);
return result;
},
@@ -133,17 +143,18 @@ export const marketUtils = {
},
constants.ZERO_AMOUNT,
);
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
feeOrders,
totalFeeAmount,
{
remainingFillableMakerAssetAmounts: remainingFillableFeeAmounts,
slippageBufferAmount,
},
);
const {
resultOrders,
remainingFillAmount,
ordersRemainingFillableMakerAssetAmounts,
} = marketUtils.findOrdersThatCoverMakerAssetFillAmount(feeOrders, totalFeeAmount, {
remainingFillableMakerAssetAmounts: remainingFillableFeeAmounts,
slippageBufferAmount,
});
return {
resultFeeOrders: resultOrders,
remainingFeeAmount: remainingFillAmount,
feeOrdersRemainingFillableMakerAssetAmounts: ordersRemainingFillableMakerAssetAmounts,
};
// TODO: add more orders here to cover rounding
// https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarding-contract-specification.md#over-buying-zrx

View File

@@ -114,7 +114,7 @@ export class OrderStateUtils {
* @return State relevant to the signedOrder, as well as whether the signedOrder is "valid".
* Validity is defined as a non-zero amount of the order can still be filled.
*/
public async getOpenOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
public async getOpenOrderStateAsync(signedOrder: SignedOrder, transactionHash?: string): Promise<OrderState> {
const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
@@ -134,6 +134,7 @@ export class OrderStateUtils {
isValid: true,
orderHash,
orderRelevantState,
transactionHash,
};
return orderState;
} else {
@@ -141,6 +142,7 @@ export class OrderStateUtils {
isValid: false,
orderHash,
error: orderValidationResult.error,
transactionHash,
};
return orderState;
}

View File

@@ -72,10 +72,12 @@ export interface FindFeeOrdersThatCoverFeesForTargetOrdersOpts {
export interface FeeOrdersAndRemainingFeeAmount<T> {
resultFeeOrders: T[];
feeOrdersRemainingFillableMakerAssetAmounts: BigNumber[];
remainingFeeAmount: BigNumber;
}
export interface OrdersAndRemainingFillAmount<T> {
resultOrders: T[];
ordersRemainingFillableMakerAssetAmounts: BigNumber[];
remainingFillAmount: BigNumber;
}

View File

@@ -120,5 +120,25 @@ describe('OrderStateUtils', () => {
const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder);
expect(orderState.isValid).to.eq(false);
});
it('should include the transactionHash in orderState if supplied in method invocation', async () => {
const makerAssetAmount = new BigNumber(10);
const takerAssetAmount = new BigNumber(10000000000000000);
const takerBalance = takerAssetAmount;
const orderFilledAmount = new BigNumber(0);
const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance);
const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount);
const [signedOrder] = testOrderFactory.generateTestSignedOrders(
{
makerAssetAmount,
takerAssetAmount,
},
1,
);
const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher);
const transactionHash = '0xdeadbeef';
const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder, transactionHash);
expect(orderState.transactionHash).to.eq(transactionHash);
});
});
});

View File

@@ -1,12 +1,42 @@
[
{
"timestamp": 1537541580,
"version": "2.0.0",
"changes": [
{
"note":
"Fixes dropped events issue by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too.",
"pr": 1080
},
{
"note":
"Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it",
"pr": 1080
},
{
"note":
"Add `transactionHash` to `OrderState` emitted by `OrderWatcher` subscriptions if the order's state change originated from a transaction.",
"pr": 1087
}
],
"timestamp": 1537907159
},
{
"version": "1.0.5",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1537875740
},
{
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
],
"timestamp": 1537541580
},
{
"version": "1.0.3",

View File

@@ -5,6 +5,16 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.0 - _September 25, 2018_
* Fixes dropped events issue by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too. (#1080)
* Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it (#1080)
* Add `transactionHash` to `OrderState` emitted by `OrderWatcher` subscriptions if the order's state change originated from a transaction. (#1087)
## v1.0.5 - _September 25, 2018_
* Dependencies updated
## v1.0.4 - _September 21, 2018_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/order-watcher",
"version": "1.0.4",
"version": "2.0.0",
"description": "An order watcher daemon that watches for order validity",
"keywords": [
"0x",
@@ -42,9 +42,9 @@
"node": ">=6.0.0"
},
"devDependencies": {
"@0xproject/abi-gen": "^1.0.9",
"@0xproject/dev-utils": "^1.0.8",
"@0xproject/migrations": "^1.0.10",
"@0xproject/abi-gen": "^1.0.11",
"@0xproject/dev-utils": "^1.0.10",
"@0xproject/migrations": "^1.0.12",
"@0xproject/tslint-config": "^1.0.7",
"@types/bintrees": "^1.0.2",
"@types/lodash": "4.14.104",
@@ -70,19 +70,19 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0xproject/assert": "^1.0.9",
"@0xproject/base-contract": "^2.0.3",
"@0xproject/contract-wrappers": "^1.0.4",
"@0xproject/fill-scenarios": "^1.0.3",
"@0xproject/json-schemas": "^1.0.2",
"@0xproject/order-utils": "^1.0.3",
"@0xproject/types": "^1.0.2",
"@0xproject/typescript-typings": "^2.0.1",
"@0xproject/utils": "^1.0.9",
"@0xproject/web3-wrapper": "^2.0.3",
"@0xproject/assert": "^1.0.11",
"@0xproject/base-contract": "^2.0.5",
"@0xproject/contract-wrappers": "^2.0.0",
"@0xproject/fill-scenarios": "^1.0.5",
"@0xproject/json-schemas": "^1.0.4",
"@0xproject/order-utils": "^1.0.5",
"@0xproject/types": "^1.1.1",
"@0xproject/typescript-typings": "^2.0.2",
"@0xproject/utils": "^1.0.11",
"@0xproject/web3-wrapper": "^3.0.1",
"bintrees": "^1.0.2",
"ethereum-types": "^1.0.7",
"ethereumjs-blockstream": "5.0.0",
"ethereum-types": "^1.0.8",
"ethereumjs-blockstream": "6.0.0",
"ethers": "3.0.22",
"lodash": "^4.17.5"
},

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