Compare commits
337 Commits
@0xproject
...
@0xproject
Author | SHA1 | Date | |
---|---|---|---|
|
1b35a6e3b5 | ||
|
900a8aee76 | ||
|
adf5acd5c4 | ||
|
b40861747b | ||
|
b73df28454 | ||
|
5afc739397 | ||
|
9eecf3683b | ||
|
7570f3db51 | ||
|
977d55c61b | ||
|
78ef98c27c | ||
|
411813d8d9 | ||
|
64f41259eb | ||
|
fc3acec669 | ||
|
b85db17e75 | ||
|
a05530f821 | ||
|
173b36c54c | ||
|
55ca971186 | ||
|
284930eb58 | ||
|
902691e289 | ||
|
0afe55f2ff | ||
|
21910a7129 | ||
|
9c89d1e99b | ||
|
408f573188 | ||
|
6f2ab23bd0 | ||
|
b830c28d83 | ||
|
4a316571ff | ||
|
5e1a2bd972 | ||
|
fc33eacd2c | ||
|
748a8a8ae3 | ||
|
7516959c9f | ||
|
311b925919 | ||
|
5d88a56452 | ||
|
ebddf82819 | ||
|
d0448c2bbd | ||
|
d8d1c98a40 | ||
|
f49b231e91 | ||
|
7a43e19116 | ||
|
e4b664bafa | ||
|
8bce407aec | ||
|
7a5376621f | ||
|
29f6adc2ed | ||
|
5446de6308 | ||
|
5e84e9689f | ||
|
9540db2aad | ||
|
7dd28d6fab | ||
|
1bfaefb240 | ||
|
c48cf3ab3b | ||
|
c64dcec772 | ||
|
45dc2be083 | ||
|
31f6fc065f | ||
|
8dea48ebef | ||
|
97150cf55f | ||
|
b0484eafe3 | ||
|
1b799e98e8 | ||
|
e6840c60c7 | ||
|
ba59879e7f | ||
|
c10807c4e3 | ||
|
4e8ec2359d | ||
|
cbd72b6e3d | ||
|
fcca63a2dc | ||
|
90e28220fa | ||
|
35c324f67c | ||
|
03e18ff7c6 | ||
|
d23487bda9 | ||
|
3238925aa4 | ||
|
abd308455a | ||
|
a44f77a838 | ||
|
3e70ab015b | ||
|
dab7f1a739 | ||
|
f6438725eb | ||
|
a03b1d4d6c | ||
|
14345ab24e | ||
|
60e2dfdbda | ||
|
83ffbd05be | ||
|
88be6b5e0d | ||
|
aa47f85f48 | ||
|
fec9c8f1c6 | ||
|
93f7e33f6a | ||
|
fd4b4f8f82 | ||
|
0003666050 | ||
|
b947609ff1 | ||
|
38afd108f8 | ||
|
65f709d50a | ||
|
f5dbf212e3 | ||
|
f6e1bf78c8 | ||
|
950f279508 | ||
|
e46807c28b | ||
|
e2559798df | ||
|
ccc18620bf | ||
|
febe00db4f | ||
|
6f36048a8e | ||
|
2457ecb7e7 | ||
|
2378747570 | ||
|
2df569b727 | ||
|
65aecc0024 | ||
|
074082ec94 | ||
|
6b9f0af828 | ||
|
bfabf765e3 | ||
|
e74f736eff | ||
|
45483557a5 | ||
|
a22d2dc7ee | ||
|
9ec2b5a2d5 | ||
|
af40989f5f | ||
|
d57619b5db | ||
|
c692115cdc | ||
|
dfe58e4975 | ||
|
4e59be9afc | ||
|
190bf2599c | ||
|
f1a22e9bd7 | ||
|
7b46cef83d | ||
|
8da7d39998 | ||
|
91702bbae2 | ||
|
90674d9038 | ||
|
c0a14a4a41 | ||
|
8d6132736b | ||
|
8687b9533c | ||
|
07942a7aec | ||
|
3d1b7c10e8 | ||
|
cf46d2c704 | ||
|
4434856add | ||
|
52d511df21 | ||
|
50f58f9121 | ||
|
7a20c7b946 | ||
|
ce0e60ed84 | ||
|
4ad0a6c7b7 | ||
|
b8d8651e43 | ||
|
45b68832aa | ||
|
6dfcaaf889 | ||
|
8131c5d6bc | ||
|
df5779b6d1 | ||
|
4a5a0c8c78 | ||
|
b3a17624c8 | ||
|
e63841a604 | ||
|
7ec95e8c29 | ||
|
b217495465 | ||
|
db6ddc0c4b | ||
|
174b360593 | ||
|
481a752e70 | ||
|
38acdfd632 | ||
|
561e525778 | ||
|
69eb820d0d | ||
|
447f16fc4f | ||
|
1769609245 | ||
|
e1dcdac1bb | ||
|
9d45d19c80 | ||
|
9858bb0ce4 | ||
|
a3527a77a6 | ||
|
33a45fa739 | ||
|
e70882a657 | ||
|
e456332da7 | ||
|
4ed84c5dc5 | ||
|
2fe3f40be9 | ||
|
44bfdb718f | ||
|
3524efc41c | ||
|
01210c291c | ||
|
192d4b4dbf | ||
|
68246fc335 | ||
|
7ef86636aa | ||
|
a5859c6cee | ||
|
3463903d02 | ||
|
4b0f1a8431 | ||
|
603e8aa671 | ||
|
6eb980abe2 | ||
|
46b168e10f | ||
|
508e6ccf89 | ||
|
a173c5fc38 | ||
|
f5237f7971 | ||
|
6f7a5d00e6 | ||
|
4061723863 | ||
|
ab1b52ba87 | ||
|
16e94ecb40 | ||
|
6bb2c5877c | ||
|
a14450f367 | ||
|
85df313a7a | ||
|
66ed6b9b88 | ||
|
9304d09da6 | ||
|
e61dbbb6cf | ||
|
1690f59857 | ||
|
c916dd6ebb | ||
|
8a683b8541 | ||
|
4883b8be10 | ||
|
51760f9bdd | ||
|
6a619a4084 | ||
|
feeafa193a | ||
|
8d8528996a | ||
|
965d609829 | ||
|
a52714bcf3 | ||
|
bbfd7647a8 | ||
|
0aba5a3be4 | ||
|
61bf5864a8 | ||
|
56847a53f4 | ||
|
8324ab3af7 | ||
|
d496a7585c | ||
|
8d7f2a993a | ||
|
ed786f3e8f | ||
|
539c243733 | ||
|
40e0c829b3 | ||
|
e34b1f2f8b | ||
|
f6b6619c08 | ||
|
e480e08aa4 | ||
|
652cf7a976 | ||
|
7a8ab6fbe8 | ||
|
9deec8ec35 | ||
|
3f1586045c | ||
|
ada5563b1f | ||
|
6b41a570a5 | ||
|
cebf6bfb34 | ||
|
47a1b48ad8 | ||
|
ef82a9d2a6 | ||
|
ba6351841d | ||
|
cdc786a1e3 | ||
|
3ea137a78f | ||
|
b525ccc825 | ||
|
77acbdd3ea | ||
|
c13190ceab | ||
|
78d4fc59a5 | ||
|
f9e86c057d | ||
|
1d8e133a30 | ||
|
99fbf384fd | ||
|
cb4fcf4de7 | ||
|
675964dc5c | ||
|
6432f85eb0 | ||
|
66eef758c6 | ||
|
c64f0ba34b | ||
|
6deffb6b28 | ||
|
5802713801 | ||
|
11df29fa8e | ||
|
f4a41e80b8 | ||
|
5c655b55d3 | ||
|
63c15b6f4f | ||
|
4f2bc29744 | ||
|
2cac431c41 | ||
|
80b7a7842c | ||
|
8c7cec9822 | ||
|
971a4087d2 | ||
|
660e670d38 | ||
|
052824f4e3 | ||
|
1d5ef4d0ca | ||
|
a6440b94f4 | ||
|
01685b7622 | ||
|
397fefa8d7 | ||
|
82a01ef020 | ||
|
a224ce347e | ||
|
81ba2a8411 | ||
|
a6e8b28da5 | ||
|
e90dbf66f3 | ||
|
0be2219beb | ||
|
09b4d5e0e4 | ||
|
60f1bcf51f | ||
|
431ac3b401 | ||
|
50781bd77a | ||
|
c3361bb86e | ||
|
fd5ad69c26 | ||
|
b1f97a27f3 | ||
|
febddcb356 | ||
|
74d5af34eb | ||
|
365890291f | ||
|
0368de701f | ||
|
f5e7b7e7e0 | ||
|
038c21324e | ||
|
5d008ee83e | ||
|
d0f6933980 | ||
|
14793f30b5 | ||
|
86319291e3 | ||
|
afa2dd7374 | ||
|
1312e4caf2 | ||
|
eb4517d737 | ||
|
d80701c277 | ||
|
bf3ab1127d | ||
|
dcb12b6ad6 | ||
|
f87420a776 | ||
|
6cedf5362b | ||
|
aa833ef074 | ||
|
5f1c9cfee5 | ||
|
62b93cf2eb | ||
|
b1c5f6e8f1 | ||
|
3bc9b309f6 | ||
|
6924a2b681 | ||
|
d93d4c34f5 | ||
|
557267477e | ||
|
b9f7979e91 | ||
|
8c803ab232 | ||
|
422e5e4dd7 | ||
|
2aea820d89 | ||
|
1c3b2b7141 | ||
|
e7d5ceb9c5 | ||
|
68af0e9eb7 | ||
|
a18d0f6229 | ||
|
031807df9c | ||
|
72710be04b | ||
|
ac135d55d3 | ||
|
1d55e94659 | ||
|
86284f1c7e | ||
|
61a4ae7fc4 | ||
|
55fab3d98f | ||
|
de11b62e30 | ||
|
8e14e65b60 | ||
|
2d1d14d2e4 | ||
|
f44644ad90 | ||
|
ac1640140c | ||
|
1402a0aa22 | ||
|
f225f9e7c8 | ||
|
14fdb71a71 | ||
|
9c4c4fb19a | ||
|
5785ec0713 | ||
|
2eab0e30b7 | ||
|
2c846ff145 | ||
|
ca0dfc6610 | ||
|
0fd44ee2c1 | ||
|
7271fc0bab | ||
|
6c039bbeb1 | ||
|
38e6d26145 | ||
|
b0f210dea9 | ||
|
f7469080f9 | ||
|
fb5ea5d99f | ||
|
be2f4cbdca | ||
|
68f2dc11b4 | ||
|
d6c670dfcb | ||
|
0736c41357 | ||
|
898bd75a18 | ||
|
260313a6ae | ||
|
6a99bfa68e | ||
|
f60adbdd72 | ||
|
1be310cef4 | ||
|
ff4f86f1d6 | ||
|
f4a4fefe42 | ||
|
91a9014a50 | ||
|
ad161a973e | ||
|
103e1aa250 | ||
|
641d86cb98 | ||
|
813b2ca1fb | ||
|
ec96c3bb77 | ||
|
65120e84e2 | ||
|
374ee2db32 | ||
|
48ab151ec2 | ||
|
44a430802e | ||
|
6b03cfd40d |
@@ -2,6 +2,7 @@ version: 2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
environment:
|
||||
@@ -50,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:
|
||||
@@ -60,9 +61,10 @@ jobs:
|
||||
# initialized
|
||||
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test contracts
|
||||
test-publish:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
- image: verdaccio/verdaccio
|
||||
- image: 0xorg/verdaccio
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -88,7 +88,7 @@ packages/0x.js/src/artifacts/
|
||||
packages/order-utils/src/artifacts/
|
||||
|
||||
# unstable generated contract artifacts:
|
||||
packages/migrations/artifacts/2.0.0/
|
||||
packages/migrations/artifacts/development/
|
||||
|
||||
# generated contract watcher
|
||||
packages/0x.js/src/generated_contract_wrappers/
|
||||
@@ -99,8 +99,9 @@ packages/fill-scenarios/src/generated_contract_wrappers/
|
||||
packages/order-watcher/src/generated_contract_wrappers/
|
||||
packages/order-utils/src/generated_contract_wrappers/
|
||||
packages/migrations/src/1.0.0/contract_wrappers
|
||||
packages/migrations/src/2.0.0-testnet/contract_wrappers
|
||||
packages/migrations/src/2.0.0/contract_wrappers
|
||||
packages/migrations/src/2.0.0-beta-testnet/contract_wrappers
|
||||
packages/migrations/src/development/contract_wrappers
|
||||
|
||||
# solc-bin in sol-compiler
|
||||
packages/sol-compiler/solc_bin/
|
||||
|
@@ -8,8 +8,8 @@ lib
|
||||
/packages/order-watcher/src/generated_contract_wrappers/
|
||||
/packages/order-utils/src/generated_contract_wrappers/
|
||||
/packages/migrations/src/1.0.0/contract_wrappers
|
||||
/packages/migrations/src/2.0.0-testnet/contract_wrappers
|
||||
/packages/migrations/src/2.0.0/contract_wrappers
|
||||
/packages/migrations/src/2.0.0-beta-testnet/contract_wrappers
|
||||
/packages/0x.js/src/artifacts
|
||||
/packages/contracts/src/artifacts
|
||||
/packages/contract-wrappers/src/artifacts
|
||||
@@ -19,7 +19,9 @@ lib
|
||||
/packages/contract-wrappers/test/artifacts
|
||||
/packages/order-watcher/test/artifacts
|
||||
/packages/migrations/artifacts/1.0.0
|
||||
/packages/migrations/artifacts/2.0.0-testnet
|
||||
/packages/migrations/artifacts/2.0.0
|
||||
/packages/migrations/artifacts/2.0.0-beta-testnet
|
||||
/packages/migrations/artifacts/development
|
||||
package.json
|
||||
scripts/postpublish_utils.js
|
||||
packages/sol-cov/test/fixtures/artifacts
|
||||
|
@@ -27,15 +27,16 @@ If you're developing on 0x now or are interested in using 0x infrastructure in t
|
||||
| [`@0xproject/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
|
||||
| [`@0xproject/base-contract`](/packages/base-contract) | [](https://www.npmjs.com/package/@0xproject/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
|
||||
| [`@0xproject/connect`](/packages/connect) | [](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the Standard Relayer API |
|
||||
| [`@0xproject/sol-compiler`](/packages/sol-compiler) | [](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) | [](https://www.npmjs.com/package/@0xproject/dev-utils) | Dev utils to be shared across 0x projects and packages |
|
||||
| [`@0xproject/json-schemas`](/packages/json-schemas) | [](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
|
||||
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | [](https://www.npmjs.com/package/@0xproject/monorepo-scripts) | Monorepo scripts |
|
||||
| [`@0xproject/order-utils`](/packages/order-utils) | [](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) | [](https://www.npmjs.com/package/@0xproject/react-docs) | React documentation component for rendering TypeDoc & Doxity generated JSON |
|
||||
| [`@0xproject/react-shared`](/packages/react-shared) | [](https://www.npmjs.com/package/@0xproject/react-shared) | 0x shared react components |
|
||||
| [`@0xproject/sol-compiler`](/packages/sol-compiler) | [](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) | [](https://www.npmjs.com/package/@0xproject/sol-cov) | Solidity test coverage tool |
|
||||
| [`@0xproject/sra-spec`](/packages/sra-spec) | [](https://www.npmjs.com/package/@0xproject/sra-spec) | OpenAPI specification for the standard relayer API |
|
||||
| [`@0xproject/sra-report`](/packages/sra-report) | [](https://www.npmjs.com/package/@0xproject/sra-report) | Generate reports for standard relayer API compliance |
|
||||
| [`@0xproject/sol-cov`](/packages/sol-cov) | [](https://www.npmjs.com/package/@0xproject/sol-cov) | Solidity test coverage tool |
|
||||
| [`@0xproject/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) |
|
||||
| [`@0xproject/tslint-config`](/packages/tslint-config) | [](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
|
||||
| [`@0xproject/types`](/packages/types) | [](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |
|
||||
|
@@ -23,10 +23,11 @@
|
||||
"install:all": "yarn install",
|
||||
"wsrun": "wsrun",
|
||||
"lerna": "lerna",
|
||||
"watch": "wsrun watch_without_deps $PKG --fast-exit -r --stages --done-criteria='complete|successfully'",
|
||||
"build": "wsrun build $PKG --fast-exit -r --stages",
|
||||
"build:no_website": "wsrun build $PKG --fast-exit -r --stages --exclude @0xproject/website",
|
||||
"build:monorepo_scripts": "PKG=@0xproject/monorepo-scripts yarn build",
|
||||
"build:ts": "tsc -b",
|
||||
"watch:ts": "tsc -b -w",
|
||||
"clean": "wsrun clean $PKG --fast-exit -r --parallel",
|
||||
"remove_node_modules": "lerna clean --yes; rm -rf node_modules",
|
||||
"rebuild": "run-s clean build",
|
||||
@@ -51,6 +52,7 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.11.1",
|
||||
"source-map-support": "^0.5.6",
|
||||
"typescript": "3.0.1",
|
||||
"wsrun": "^2.2.0"
|
||||
},
|
||||
"resolutions": {
|
||||
|
@@ -1,4 +1,58 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Drastically reduce the bundle size by removing unused parts of included contract artifacts."
|
||||
}
|
||||
],
|
||||
"timestamp": 1537369748
|
||||
},
|
||||
{
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add ZRX & WETH mainnet contract addresses into the included artifacts"
|
||||
}
|
||||
],
|
||||
"timestamp": 1537265493
|
||||
},
|
||||
{
|
||||
"timestamp": 1536142250,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.6",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,30 @@ 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
|
||||
|
||||
## v1.0.3 - _September 19, 2018_
|
||||
|
||||
* Drastically reduce the bundle size by removing unused parts of included contract artifacts.
|
||||
|
||||
## v1.0.2 - _September 18, 2018_
|
||||
|
||||
* Add ZRX & WETH mainnet contract addresses into the included artifacts
|
||||
|
||||
## v1.0.1 - _September 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1-rc.6 - _August 27, 2018_
|
||||
|
||||
* Fix missing `BlockParamLiteral` type import issue
|
||||
|
@@ -1,6 +1,6 @@
|
||||
## 0x.js
|
||||
|
||||
A TypeScript/Javascript library for interacting with the 0x protocol.
|
||||
A TypeScript/Javascript library for interacting with the 0x protocol. It is a high level package which combines a number of underlying packages such as order-utils and order-watcher.
|
||||
|
||||
### Read the [Documentation](https://0xproject.com/docs/0x.js).
|
||||
|
||||
@@ -19,7 +19,14 @@ npm install 0x.js --save
|
||||
**Import**
|
||||
|
||||
```javascript
|
||||
import { ZeroEx } from '0x.js';
|
||||
import {
|
||||
assetDataUtils,
|
||||
BigNumber,
|
||||
ContractWrappers,
|
||||
generatePseudoRandomSalt,
|
||||
orderHashUtils,
|
||||
signatureUtils,
|
||||
} from '0x.js';
|
||||
```
|
||||
|
||||
If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`:
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "0x.js",
|
||||
"version": "1.0.1-rc.6",
|
||||
"version": "1.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -15,7 +15,6 @@
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"scripts": {
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "yarn build:all",
|
||||
"build:all": "run-p build:umd:prod build:commonjs",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/*",
|
||||
@@ -25,8 +24,8 @@
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"clean": "shx rm -rf _bundles lib test_temp src/generated_contract_wrappers generated_docs",
|
||||
"build:umd:prod": "NODE_ENV=production webpack",
|
||||
"build:commonjs": "tsc",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
"build:commonjs": "tsc -b",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"postpublish": {
|
||||
@@ -42,15 +41,16 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.7",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/migrations": "^1.0.6",
|
||||
"@0xproject/monorepo-scripts": "^1.0.7",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@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",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/node": "*",
|
||||
"@types/sinon": "^2.2.2",
|
||||
"@types/web3-provider-engine": "^14.0.0",
|
||||
"awesome-typescript-loader": "^3.1.3",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
@@ -73,17 +73,17 @@
|
||||
"webpack": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.7",
|
||||
"@0xproject/base-contract": "^2.0.1",
|
||||
"@0xproject/contract-wrappers": "^1.0.1-rc.5",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.6",
|
||||
"@0xproject/order-watcher": "^1.0.1-rc.5",
|
||||
"@0xproject/subproviders": "^2.0.1",
|
||||
"@0xproject/types": "^1.0.1-rc.6",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@0xproject/web3-wrapper": "^2.0.1",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"@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"
|
||||
|
@@ -9,6 +9,7 @@ export {
|
||||
ERC20ProxyWrapper,
|
||||
ERC721ProxyWrapper,
|
||||
ForwarderWrapper,
|
||||
OrderValidatorWrapper,
|
||||
IndexedFilterValues,
|
||||
BlockRange,
|
||||
ContractWrappersConfig,
|
||||
@@ -42,6 +43,10 @@ export {
|
||||
DecodedLogEvent,
|
||||
ExchangeEventArgs,
|
||||
TransactionEncoder,
|
||||
BalanceAndAllowance,
|
||||
OrderAndTraderInfo,
|
||||
TraderInfo,
|
||||
ValidateOrderFillableOpts,
|
||||
} from '@0xproject/contract-wrappers';
|
||||
|
||||
export { OrderWatcher, OnOrderStateChangeCallback, OrderWatcherConfig } from '@0xproject/order-watcher';
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
"outDir": "lib",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
"include": ["./src/**/*"]
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"extends": "../../typedoc-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
@@ -47,8 +47,13 @@ module.exports = {
|
||||
use: [
|
||||
{
|
||||
loader: 'awesome-typescript-loader',
|
||||
// tsconfig.json contains some options required for
|
||||
// project references which do not work with webback.
|
||||
// We override those options here.
|
||||
query: {
|
||||
declaration: false,
|
||||
declarationMap: false,
|
||||
composite: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1536142250,
|
||||
"version": "1.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "1.0.7",
|
||||
|
@@ -5,6 +5,22 @@ 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
|
||||
|
||||
## v1.0.8 - _September 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.7 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/abi-gen",
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.11",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -8,10 +8,9 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch_without_deps": "tsc -w",
|
||||
"lint": "tslint --project .",
|
||||
"clean": "shx rm -rf lib",
|
||||
"build": "tsc",
|
||||
"build": "tsc -b",
|
||||
"test": "yarn run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --bail --exit",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
@@ -31,10 +30,10 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@0xproject/typescript-typings": "^2.0.2",
|
||||
"@0xproject/utils": "^1.0.11",
|
||||
"chalk": "^2.3.0",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethereum-types": "^1.0.8",
|
||||
"glob": "^7.1.2",
|
||||
"handlebars": "^4.0.11",
|
||||
"lodash": "^4.17.5",
|
||||
@@ -45,11 +44,11 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.7",
|
||||
"@types/glob": "5.0.35",
|
||||
"@types/handlebars": "^4.0.36",
|
||||
"@types/mkdirp": "^0.5.1",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/node": "*",
|
||||
"@types/sleep": "^0.0.7",
|
||||
"@types/tmp": "^0.0.33",
|
||||
"@types/yargs": "^10.0.0",
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
||||
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1536142250,
|
||||
"version": "1.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "1.0.7",
|
||||
|
@@ -5,6 +5,22 @@ 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
|
||||
|
||||
## v1.0.8 - _September 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.7 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/assert",
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.11",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -8,8 +8,7 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc",
|
||||
"build": "tsc -b",
|
||||
"clean": "shx rm -rf lib test_temp",
|
||||
"lint": "tslint --project .",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --exit",
|
||||
@@ -29,7 +28,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.7",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/valid-url": "^1.0.2",
|
||||
@@ -45,9 +44,9 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.6",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@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"
|
||||
},
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
||||
|
28
packages/asset-buyer/CHANGELOG.json
Normal file
28
packages/asset-buyer/CHANGELOG.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@@ -5,10 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.2 - _August 27, 2018_
|
||||
## v1.0.1 - _September 25, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1-rc.1 - _August 24, 2018_
|
||||
## v1.0.0 - _September 25, 2018_
|
||||
|
||||
* Add initial forwarderHelperFactory (#997)
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-rc.1 - _Invalid date_
|
||||
|
||||
* Init
|
83
packages/asset-buyer/README.md
Normal file
83
packages/asset-buyer/README.md
Normal 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
|
||||
```
|
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "@0xproject/forwarder-helper",
|
||||
"version": "1.0.1-rc.2",
|
||||
"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": {
|
||||
@@ -18,10 +18,7 @@
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --exit",
|
||||
"clean": "shx rm -rf lib test_temp scripts",
|
||||
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js",
|
||||
"docs:stage": "node scripts/stage_docs.js",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES",
|
||||
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json"
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
|
||||
},
|
||||
"config": {
|
||||
"postpublish": {
|
||||
@@ -37,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.7",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.6",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.6",
|
||||
"@0xproject/types": "^1.0.1-rc.6",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@types/node": "^8.0.53",
|
||||
"@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.6",
|
||||
"@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",
|
||||
@@ -63,7 +65,7 @@
|
||||
"nyc": "^11.0.1",
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "0xProject/typedoc",
|
||||
"typedoc": "0.12.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"publishConfig": {
|
324
packages/asset-buyer/src/asset_buyer.ts
Normal file
324
packages/asset-buyer/src/asset_buyer.ts
Normal 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);
|
||||
}
|
||||
}
|
20
packages/asset-buyer/src/constants.ts
Normal file
20
packages/asset-buyer/src/constants.ts
Normal 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,
|
||||
};
|
17
packages/asset-buyer/src/index.ts
Normal file
17
packages/asset-buyer/src/index.ts
Normal 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';
|
@@ -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 };
|
||||
}
|
||||
}
|
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
86
packages/asset-buyer/src/types.ts
Normal file
86
packages/asset-buyer/src/types.ts
Normal 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[];
|
||||
}
|
51
packages/asset-buyer/src/utils/assert.ts
Normal file
51
packages/asset-buyer/src/utils/assert.ts
Normal 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}`,
|
||||
);
|
||||
},
|
||||
};
|
26
packages/asset-buyer/src/utils/asset_data_utils.ts
Normal file
26
packages/asset-buyer/src/utils/asset_data_utils.ts
Normal 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;
|
||||
},
|
||||
};
|
89
packages/asset-buyer/src/utils/buy_quote_calculator.ts
Normal file
89
packages/asset-buyer/src/utils/buy_quote_calculator.ts
Normal 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,
|
||||
};
|
||||
},
|
||||
};
|
@@ -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;
|
||||
}
|
30
packages/asset-buyer/src/utils/order_utils.ts
Normal file
30
packages/asset-buyer/src/utils/order_utils.ts
Normal 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;
|
||||
},
|
||||
};
|
8
packages/asset-buyer/tsconfig.json
Normal file
8
packages/asset-buyer/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
7
packages/asset-buyer/typedoc-tsconfig.json
Normal file
7
packages/asset-buyer/typedoc-tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../typedoc-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1536142250,
|
||||
"version": "2.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "2.0.1",
|
||||
|
@@ -5,6 +5,22 @@ 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
|
||||
|
||||
## v2.0.2 - _September 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.1 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/base-contract",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -8,8 +8,7 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc",
|
||||
"build": "tsc -b",
|
||||
"clean": "shx rm -rf lib",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
@@ -29,7 +28,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.7",
|
||||
"@types/lodash": "4.14.104",
|
||||
"chai": "^4.0.1",
|
||||
"copyfiles": "^2.0.0",
|
||||
@@ -41,10 +40,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@0xproject/web3-wrapper": "^2.0.1",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"@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"
|
||||
},
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["src/**/*", "test/**/*"]
|
||||
}
|
||||
|
@@ -1,4 +1,51 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1537369748,
|
||||
"version": "2.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Change `OrderConfigRequest` to use BigNumber instead of string for relevant fields.",
|
||||
"pr": 1058
|
||||
}
|
||||
],
|
||||
"timestamp": 1536142250
|
||||
},
|
||||
{
|
||||
"version": "2.0.0-rc.2",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,26 @@ 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
|
||||
|
||||
## v2.0.1 - _September 19, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.0 - _September 5, 2018_
|
||||
|
||||
* Change `OrderConfigRequest` to use BigNumber instead of string for relevant fields. (#1058)
|
||||
|
||||
## v2.0.0-rc.2 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/connect",
|
||||
"version": "2.0.0-rc.2",
|
||||
"version": "2.0.4",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -15,8 +15,7 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc",
|
||||
"build": "tsc -b",
|
||||
"clean": "shx rm -rf lib test_temp generated_docs",
|
||||
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
|
||||
"lint": "tslint --project .",
|
||||
@@ -26,7 +25,7 @@
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"postpublish": {
|
||||
@@ -44,11 +43,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.7",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.6",
|
||||
"@0xproject/types": "^1.0.1-rc.6",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@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",
|
||||
@@ -56,7 +56,7 @@
|
||||
"websocket": "^1.0.25"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.7",
|
||||
"@types/fetch-mock": "^6.0.3",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
|
@@ -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;
|
||||
@@ -151,7 +149,7 @@ export class HttpClient implements Client {
|
||||
params: requestOpts,
|
||||
payload: request,
|
||||
};
|
||||
const responseJson = await this._requestAsync('/order_config', HttpRequestType.Post, httpRequestOpts);
|
||||
const responseJson = await this._requestAsync('/order_config', HttpRequestType.Get, httpRequestOpts);
|
||||
const fees = relayerResponseJsonParsers.parseOrderConfigResponseJson(responseJson);
|
||||
return fees;
|
||||
}
|
||||
|
@@ -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';
|
||||
|
@@ -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: string;
|
||||
takerAssetAmount: string;
|
||||
makerAssetData: string;
|
||||
takerAssetData: string;
|
||||
exchangeAddress: string;
|
||||
expirationTimeSeconds: string;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@@ -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';
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { assert } from '@0xproject/assert';
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { orderParsingUtils } from '@0xproject/order-utils';
|
||||
|
||||
import {
|
||||
APIOrder,
|
||||
@@ -8,7 +9,7 @@ import {
|
||||
OrderbookResponse,
|
||||
OrderConfigResponse,
|
||||
OrdersResponse,
|
||||
} from '../types';
|
||||
} from '@0xproject/types';
|
||||
|
||||
import { typeConverters } from './type_converters';
|
||||
|
||||
@@ -19,7 +20,7 @@ export const relayerResponseJsonParsers = {
|
||||
},
|
||||
parseAssetPairsItemsJson(json: any): AssetPairsItem[] {
|
||||
return json.map((assetDataPair: any) => {
|
||||
return typeConverters.convertStringsFieldsToBigNumbers(assetDataPair, [
|
||||
return orderParsingUtils.convertStringsFieldsToBigNumbers(assetDataPair, [
|
||||
'assetDataA.minAmount',
|
||||
'assetDataA.maxAmount',
|
||||
'assetDataB.minAmount',
|
||||
@@ -44,6 +45,6 @@ export const relayerResponseJsonParsers = {
|
||||
},
|
||||
parseOrderConfigResponseJson(json: any): OrderConfigResponse {
|
||||
assert.doesConformToSchema('orderConfigResponse', json, schemas.relayerApiOrderConfigResponseSchema);
|
||||
return typeConverters.convertStringsFieldsToBigNumbers(json, ['makerFee', 'takerFee']);
|
||||
return orderParsingUtils.convertStringsFieldsToBigNumbers(json, ['makerFee', 'takerFee']);
|
||||
},
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
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 {
|
||||
@@ -21,28 +21,6 @@ export const typeConverters = {
|
||||
};
|
||||
},
|
||||
convertAPIOrderStringFieldsToBigNumber(apiOrder: any): APIOrder {
|
||||
return { ...apiOrder, order: typeConverters.convertOrderStringFieldsToBigNumber(apiOrder.order) };
|
||||
},
|
||||
convertOrderStringFieldsToBigNumber(order: any): any {
|
||||
return typeConverters.convertStringsFieldsToBigNumbers(order, [
|
||||
'makerAssetAmount',
|
||||
'takerAssetAmount',
|
||||
'makerFee',
|
||||
'takerFee',
|
||||
'expirationTimeSeconds',
|
||||
'salt',
|
||||
]);
|
||||
},
|
||||
convertStringsFieldsToBigNumbers(obj: any, fields: string[]): any {
|
||||
const result = _.assign({}, obj);
|
||||
_.each(fields, field => {
|
||||
_.update(result, field, (value: string) => {
|
||||
if (_.isUndefined(value)) {
|
||||
throw new Error(`Could not find field '${field}' while converting string fields to BigNumber.`);
|
||||
}
|
||||
return new BigNumber(value);
|
||||
});
|
||||
});
|
||||
return result;
|
||||
return { ...apiOrder, order: orderParsingUtils.convertOrderStringFieldsToBigNumber(apiOrder.order) };
|
||||
},
|
||||
};
|
||||
|
@@ -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';
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { FeeRecipientsResponse } from '../../../src/types';
|
||||
import { FeeRecipientsResponse } from '@0xproject/types';
|
||||
|
||||
export const feeRecipientsResponse: FeeRecipientsResponse = {
|
||||
total: 3,
|
||||
|
@@ -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',
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
import { OrderbookResponse } from '../../../src/types';
|
||||
import { OrderbookResponse } from '@0xproject/types';
|
||||
|
||||
export const orderbookResponse: OrderbookResponse = {
|
||||
bids: {
|
||||
|
@@ -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,
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
@@ -138,21 +139,21 @@ describe('HttpClient', () => {
|
||||
const request = {
|
||||
makerAddress: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||
takerAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||
makerAssetAmount: '10000000000000000',
|
||||
takerAssetAmount: '20000000000000000',
|
||||
expirationTimeSeconds: '1532560590',
|
||||
makerAssetAmount: new BigNumber('10000000000000000'),
|
||||
takerAssetAmount: new BigNumber('20000000000000000'),
|
||||
expirationTimeSeconds: new BigNumber('1532560590'),
|
||||
makerAssetData: '0xf47261b04c32345ced77393b3530b1eed0f346429d',
|
||||
takerAssetData: '0x0257179264389b814a946f3e92105513705ca6b990',
|
||||
exchangeAddress: '0x12459c951127e0c374ff9105dda097662a027093',
|
||||
};
|
||||
const url = `${relayUrl}/order_config`;
|
||||
it('gets order config', async () => {
|
||||
fetchMock.post(url, orderConfigResponseJSON);
|
||||
fetchMock.get(url, orderConfigResponseJSON);
|
||||
const fees = await relayerClient.getOrderConfigAsync(request);
|
||||
expect(fees).to.be.deep.equal(orderConfigResponse);
|
||||
});
|
||||
it('does not mutate input', async () => {
|
||||
fetchMock.post(url, orderConfigResponseJSON);
|
||||
fetchMock.get(url, orderConfigResponseJSON);
|
||||
const makerAssetAmountBefore = request.makerAssetAmount;
|
||||
const takerAssetAmountBefore = request.takerAssetAmount;
|
||||
const expirationTimeSecondsBefore = request.expirationTimeSeconds;
|
||||
@@ -162,7 +163,7 @@ describe('HttpClient', () => {
|
||||
expect(expirationTimeSecondsBefore).to.be.deep.equal(request.expirationTimeSeconds);
|
||||
});
|
||||
it('throws an error for invalid JSON response', async () => {
|
||||
fetchMock.post(url, { test: 'dummy' });
|
||||
fetchMock.get(url, { test: 'dummy' });
|
||||
expect(relayerClient.getOrderConfigAsync(request)).to.be.rejected();
|
||||
});
|
||||
});
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
||||
|
7
packages/connect/typedoc-tsconfig.json
Normal file
7
packages/connect/typedoc-tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../typedoc-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
@@ -1,4 +1,80 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Drastically reduce the bundle size by removing unused parts of included contract artifacts."
|
||||
}
|
||||
],
|
||||
"timestamp": 1537369748
|
||||
},
|
||||
{
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add ZRX & WETH mainnet contract addresses into the included artifacts"
|
||||
}
|
||||
],
|
||||
"timestamp": 1537265493
|
||||
},
|
||||
{
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `OrderValidatorWrapper`"
|
||||
},
|
||||
{
|
||||
"note":
|
||||
"Fix bug where contracts not deployed on a network showed an `EXCHANGE_CONTRACT_DOES_NOT_EXIST` error instead of `CONTRACT_NOT_DEPLOYED_ON_NETWORK`",
|
||||
"pr": 1044
|
||||
},
|
||||
{
|
||||
"note":
|
||||
"Export `AssetBalanceAndProxyAllowanceFetcher` and `OrderFilledCancelledFetcher` implementations",
|
||||
"pr": 1054
|
||||
},
|
||||
{
|
||||
"note":
|
||||
"Add `validateOrderFillableOrThrowAsync` and `validateFillOrderThrowIfInvalidAsync` to ExchangeWrapper",
|
||||
"pr": 1054
|
||||
}
|
||||
],
|
||||
"timestamp": 1536142250
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,34 @@ 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
|
||||
|
||||
## v1.0.3 - _September 19, 2018_
|
||||
|
||||
* Drastically reduce the bundle size by removing unused parts of included contract artifacts.
|
||||
|
||||
## v1.0.2 - _September 18, 2018_
|
||||
|
||||
* Add ZRX & WETH mainnet contract addresses into the included artifacts
|
||||
|
||||
## v1.0.1 - _September 5, 2018_
|
||||
|
||||
* Add `OrderValidatorWrapper`
|
||||
* Fix bug where contracts not deployed on a network showed an `EXCHANGE_CONTRACT_DOES_NOT_EXIST` error instead of `CONTRACT_NOT_DEPLOYED_ON_NETWORK` (#1044)
|
||||
* Export `AssetBalanceAndProxyAllowanceFetcher` and `OrderFilledCancelledFetcher` implementations (#1054)
|
||||
* Add `validateOrderFillableOrThrowAsync` and `validateFillOrderThrowIfInvalidAsync` to ExchangeWrapper (#1054)
|
||||
|
||||
## v1.0.1-rc.5 - _August 27, 2018_
|
||||
|
||||
* Fix missing `BlockParamLiteral` type import issue
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/contract-wrappers",
|
||||
"version": "1.0.1-rc.5",
|
||||
"version": "2.0.0",
|
||||
"description": "Smart TS wrappers for 0x smart contracts",
|
||||
"keywords": [
|
||||
"0xproject",
|
||||
@@ -11,26 +11,23 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && tsc",
|
||||
"pre_build": "run-s update_artifacts_v2_beta update_artifacts_v2 generate_contract_wrappers copy_artifacts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/artifacts/@(Exchange|DummyERC20Token|DummyERC721Token|ZRXToken|ERC20Token|ERC721Token|WETH9|ERC20Proxy|ERC721Proxy|Forwarder).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers",
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"pre_build": "run-s update_artifacts generate_contract_wrappers copy_artifacts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/artifacts/@(Exchange|DummyERC20Token|DummyERC721Token|ZRXToken|ERC20Token|ERC721Token|WETH9|ERC20Proxy|ERC721Proxy|Forwarder|OrderValidator).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"test:circleci": "run-s test:coverage",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"update_artifacts_v2_beta": "for i in ${npm_package_config_contracts_v2_beta}; do copyfiles -u 4 ../migrations/artifacts/2.0.0-beta-testnet/$i.json src/artifacts; done;",
|
||||
"update_artifacts_v2": "for i in ${npm_package_config_contracts_v2}; do copyfiles -u 4 ../migrations/artifacts/2.0.0/$i.json src/artifacts; done;",
|
||||
"update_artifacts": "for i in ${npm_package_config_contracts_v2}; do copyfiles -u 4 ../migrations/artifacts/2.0.0-trimmed/$i.json src/artifacts; done;",
|
||||
"copy_artifacts": "copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts",
|
||||
"clean": "shx rm -rf _bundles lib test_temp test/artifacts src/contract_wrappers/generated src/artifacts generated_docs",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"contracts_v2_beta": "AssetProxyOwner Exchange ERC20Proxy ERC20Token ERC721Proxy ERC721Token WETH9 ZRXToken Forwarder OrderValidator",
|
||||
"contracts_v2": "DummyERC20Token DummyERC721Token",
|
||||
"contracts_v2": "AssetProxyOwner Exchange ERC20Proxy ERC20Token ERC721Proxy ERC721Token WETH9 ZRXToken Forwarder OrderValidator DummyERC20Token DummyERC721Token",
|
||||
"postpublish": {
|
||||
"assets": []
|
||||
}
|
||||
@@ -44,16 +41,17 @@
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.7",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/migrations": "^1.0.6",
|
||||
"@0xproject/subproviders": "^2.0.1",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@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",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/node": "*",
|
||||
"@types/sinon": "^2.2.2",
|
||||
"@types/uuid": "^3.4.2",
|
||||
"@types/web3-provider-engine": "^14.0.0",
|
||||
"awesome-typescript-loader": "^3.1.3",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
@@ -74,17 +72,17 @@
|
||||
"web3-provider-engine": "14.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.7",
|
||||
"@0xproject/base-contract": "^2.0.1",
|
||||
"@0xproject/fill-scenarios": "^1.0.1-rc.5",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.6",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.6",
|
||||
"@0xproject/types": "^1.0.1-rc.6",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@0xproject/web3-wrapper": "^2.0.1",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"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",
|
||||
|
@@ -8,6 +8,7 @@ import * as ERC721Proxy from './artifacts/ERC721Proxy.json';
|
||||
import * as ERC721Token from './artifacts/ERC721Token.json';
|
||||
import * as Exchange from './artifacts/Exchange.json';
|
||||
import * as Forwarder from './artifacts/Forwarder.json';
|
||||
import * as OrderValidator from './artifacts/OrderValidator.json';
|
||||
import * as EtherToken from './artifacts/WETH9.json';
|
||||
import * as ZRXToken from './artifacts/ZRXToken.json';
|
||||
|
||||
@@ -22,4 +23,5 @@ export const artifacts = {
|
||||
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
|
||||
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
|
||||
Forwarder: (Forwarder as any) as ContractArtifact,
|
||||
OrderValidator: (OrderValidator as any) as ContractArtifact,
|
||||
};
|
||||
|
@@ -12,6 +12,7 @@ import { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper';
|
||||
import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
|
||||
import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
|
||||
import { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
|
||||
import { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper';
|
||||
import { ContractWrappersConfigSchema } from './schemas/contract_wrappers_config_schema';
|
||||
import { contractWrappersPrivateNetworkConfigSchema } from './schemas/contract_wrappers_private_network_config_schema';
|
||||
import { contractWrappersPublicNetworkConfigSchema } from './schemas/contract_wrappers_public_network_config_schema';
|
||||
@@ -52,6 +53,10 @@ export class ContractWrappers {
|
||||
* An instance of the ForwarderWrapper class containing methods for interacting with any Forwarder smart contract.
|
||||
*/
|
||||
public forwarder: ForwarderWrapper;
|
||||
/**
|
||||
* An instance of the OrderValidatorWrapper class containing methods for interacting with any OrderValidator smart contract.
|
||||
*/
|
||||
public orderValidator: OrderValidatorWrapper;
|
||||
|
||||
private _web3Wrapper: Web3Wrapper;
|
||||
/**
|
||||
@@ -106,6 +111,8 @@ export class ContractWrappers {
|
||||
this.exchange = new ExchangeWrapper(
|
||||
this._web3Wrapper,
|
||||
config.networkId,
|
||||
this.erc20Token,
|
||||
this.erc721Token,
|
||||
config.exchangeContractAddress,
|
||||
config.zrxContractAddress,
|
||||
blockPollingIntervalMs,
|
||||
@@ -116,6 +123,7 @@ export class ContractWrappers {
|
||||
config.forwarderContractAddress,
|
||||
config.zrxContractAddress,
|
||||
);
|
||||
this.orderValidator = new OrderValidatorWrapper(this._web3Wrapper, config.networkId);
|
||||
}
|
||||
/**
|
||||
* Sets a new web3 provider for 0x.js. Updating the provider will stop all
|
||||
|
@@ -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';
|
||||
@@ -145,16 +146,20 @@ export abstract class ContractWrapper {
|
||||
}
|
||||
protected _getContractAddress(artifact: ContractArtifact, addressIfExists?: string): string {
|
||||
if (_.isUndefined(addressIfExists)) {
|
||||
if (_.isUndefined(artifact.networks[this._networkId])) {
|
||||
throw new Error(ContractWrappersError.ContractNotDeployedOnNetwork);
|
||||
}
|
||||
const contractAddress = artifact.networks[this._networkId].address;
|
||||
if (_.isUndefined(contractAddress)) {
|
||||
throw new Error(ContractWrappersError.ExchangeContractDoesNotExist);
|
||||
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contractName]);
|
||||
}
|
||||
return contractAddress;
|
||||
} else {
|
||||
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>;
|
||||
@@ -171,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 = {};
|
||||
@@ -191,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
|
||||
@@ -209,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,19 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { assetDataUtils } from '@0xproject/order-utils';
|
||||
import {
|
||||
assetDataUtils,
|
||||
BalanceAndProxyAllowanceLazyStore,
|
||||
ExchangeTransferSimulator,
|
||||
OrderValidationUtils,
|
||||
} from '@0xproject/order-utils';
|
||||
import { AssetProxyId, Order, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
|
||||
import { BlockParamLiteral, ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { AssetBalanceAndProxyAllowanceFetcher } from '../fetchers/asset_balance_and_proxy_allowance_fetcher';
|
||||
import { OrderFilledCancelledFetcher } from '../fetchers/order_filled_cancelled_fetcher';
|
||||
import { methodOptsSchema } from '../schemas/method_opts_schema';
|
||||
import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
|
||||
import { txOptsSchema } from '../schemas/tx_opts_schema';
|
||||
@@ -17,13 +24,17 @@ import {
|
||||
IndexedFilterValues,
|
||||
MethodOpts,
|
||||
OrderInfo,
|
||||
OrderStatus,
|
||||
OrderTransactionOpts,
|
||||
ValidateOrderFillableOpts,
|
||||
} from '../types';
|
||||
import { assert } from '../utils/assert';
|
||||
import { decorators } from '../utils/decorators';
|
||||
import { TransactionEncoder } from '../utils/transaction_encoder';
|
||||
|
||||
import { ContractWrapper } from './contract_wrapper';
|
||||
import { ERC20TokenWrapper } from './erc20_token_wrapper';
|
||||
import { ERC721TokenWrapper } from './erc721_token_wrapper';
|
||||
import { ExchangeContract, ExchangeEventArgs, ExchangeEvents } from './generated/exchange';
|
||||
|
||||
/**
|
||||
@@ -33,6 +44,8 @@ import { ExchangeContract, ExchangeEventArgs, ExchangeEvents } from './generated
|
||||
export class ExchangeWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.Exchange.compilerOutput.abi;
|
||||
private _exchangeContractIfExists?: ExchangeContract;
|
||||
private _erc721TokenWrapper: ERC721TokenWrapper;
|
||||
private _erc20TokenWrapper: ERC20TokenWrapper;
|
||||
private _contractAddressIfExists?: string;
|
||||
private _zrxContractAddressIfExists?: string;
|
||||
/**
|
||||
@@ -48,11 +61,15 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
constructor(
|
||||
web3Wrapper: Web3Wrapper,
|
||||
networkId: number,
|
||||
erc20TokenWrapper: ERC20TokenWrapper,
|
||||
erc721TokenWrapper: ERC721TokenWrapper,
|
||||
contractAddressIfExists?: string,
|
||||
zrxContractAddressIfExists?: string,
|
||||
blockPollingIntervalMs?: number,
|
||||
) {
|
||||
super(web3Wrapper, networkId, blockPollingIntervalMs);
|
||||
this._erc20TokenWrapper = erc20TokenWrapper;
|
||||
this._erc721TokenWrapper = erc721TokenWrapper;
|
||||
this._contractAddressIfExists = contractAddressIfExists;
|
||||
this._zrxContractAddressIfExists = zrxContractAddressIfExists;
|
||||
}
|
||||
@@ -1084,6 +1101,64 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
/**
|
||||
* Validate if the supplied order is fillable, and throw if it isn't
|
||||
* @param signedOrder SignedOrder of interest
|
||||
* @param opts ValidateOrderFillableOpts options (e.g expectedFillTakerTokenAmount.
|
||||
* If it isn't supplied, we check if the order is fillable for a non-zero amount)
|
||||
*/
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
signedOrder: SignedOrder,
|
||||
opts: ValidateOrderFillableOpts = {},
|
||||
): Promise<void> {
|
||||
const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher(
|
||||
this._erc20TokenWrapper,
|
||||
this._erc721TokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const balanceAllowanceStore = new BalanceAndProxyAllowanceLazyStore(balanceAllowanceFetcher);
|
||||
const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore);
|
||||
|
||||
const expectedFillTakerTokenAmountIfExists = opts.expectedFillTakerTokenAmount;
|
||||
const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest);
|
||||
const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher);
|
||||
await orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeSimulator,
|
||||
signedOrder,
|
||||
this.getZRXAssetData(),
|
||||
expectedFillTakerTokenAmountIfExists,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Validate a call to FillOrder and throw if it wouldn't succeed
|
||||
* @param signedOrder SignedOrder of interest
|
||||
* @param fillTakerAssetAmount Amount we'd like to fill the order for
|
||||
* @param takerAddress The taker of the order
|
||||
*/
|
||||
public async validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerAssetAmount: BigNumber,
|
||||
takerAddress: string,
|
||||
): Promise<void> {
|
||||
const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher(
|
||||
this._erc20TokenWrapper,
|
||||
this._erc721TokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const balanceAllowanceStore = new BalanceAndProxyAllowanceLazyStore(balanceAllowanceFetcher);
|
||||
const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore);
|
||||
|
||||
const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest);
|
||||
const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher);
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeSimulator,
|
||||
this._web3Wrapper.getProvider(),
|
||||
signedOrder,
|
||||
fillTakerAssetAmount,
|
||||
takerAddress,
|
||||
this.getZRXAssetData(),
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Retrieves the Ethereum address of the Exchange contract deployed on the network
|
||||
* that the user-passed web3 provider is connected to.
|
||||
|
@@ -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,
|
||||
|
@@ -0,0 +1,187 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { ContractAbi } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { BalanceAndAllowance, OrderAndTraderInfo, TraderInfo } from '../types';
|
||||
import { assert } from '../utils/assert';
|
||||
|
||||
import { ContractWrapper } from './contract_wrapper';
|
||||
import { OrderValidatorContract } from './generated/order_validator';
|
||||
|
||||
/**
|
||||
* This class includes the functionality related to interacting with the OrderValidator contract.
|
||||
*/
|
||||
export class OrderValidatorWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.OrderValidator.compilerOutput.abi;
|
||||
private _orderValidatorContractIfExists?: OrderValidatorContract;
|
||||
/**
|
||||
* Instantiate OrderValidatorWrapper
|
||||
* @param web3Wrapper Web3Wrapper instance to use
|
||||
* @param networkId Desired networkId
|
||||
*/
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number) {
|
||||
super(web3Wrapper, networkId);
|
||||
}
|
||||
/**
|
||||
* Get an object conforming to OrderAndTraderInfo containing on-chain information of the provided order and address
|
||||
* @param order An object conforming to SignedOrder
|
||||
* @param takerAddress An ethereum address
|
||||
* @return OrderAndTraderInfo
|
||||
*/
|
||||
public async getOrderAndTraderInfoAsync(order: SignedOrder, takerAddress: string): Promise<OrderAndTraderInfo> {
|
||||
assert.doesConformToSchema('order', order, schemas.signedOrderSchema);
|
||||
assert.isETHAddressHex('takerAddress', takerAddress);
|
||||
const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
|
||||
const orderAndTraderInfo = await OrderValidatorContractInstance.getOrderAndTraderInfo.callAsync(
|
||||
order,
|
||||
takerAddress,
|
||||
);
|
||||
const result = {
|
||||
orderInfo: orderAndTraderInfo[0],
|
||||
traderInfo: orderAndTraderInfo[1],
|
||||
};
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get an array of objects conforming to OrderAndTraderInfo containing on-chain information of the provided orders and addresses
|
||||
* @param orders An array of objects conforming to SignedOrder
|
||||
* @param takerAddresses An array of ethereum addresses
|
||||
* @return array of OrderAndTraderInfo
|
||||
*/
|
||||
public async getOrdersAndTradersInfoAsync(
|
||||
orders: SignedOrder[],
|
||||
takerAddresses: string[],
|
||||
): Promise<OrderAndTraderInfo[]> {
|
||||
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
|
||||
_.forEach(takerAddresses, (takerAddress, index) =>
|
||||
assert.isETHAddressHex(`takerAddresses[${index}]`, takerAddress),
|
||||
);
|
||||
assert.assert(orders.length === takerAddresses.length, 'Expected orders.length to equal takerAddresses.length');
|
||||
const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
|
||||
const ordersAndTradersInfo = await OrderValidatorContractInstance.getOrdersAndTradersInfo.callAsync(
|
||||
orders,
|
||||
takerAddresses,
|
||||
);
|
||||
const orderInfos = ordersAndTradersInfo[0];
|
||||
const traderInfos = ordersAndTradersInfo[1];
|
||||
const result = _.map(orderInfos, (orderInfo, index) => {
|
||||
const traderInfo = traderInfos[index];
|
||||
return {
|
||||
orderInfo,
|
||||
traderInfo,
|
||||
};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get an object conforming to TraderInfo containing on-chain balance and allowances for maker and taker of order
|
||||
* @param order An object conforming to SignedOrder
|
||||
* @param takerAddress An ethereum address
|
||||
* @return TraderInfo
|
||||
*/
|
||||
public async getTraderInfoAsync(order: SignedOrder, takerAddress: string): Promise<TraderInfo> {
|
||||
assert.doesConformToSchema('order', order, schemas.signedOrderSchema);
|
||||
assert.isETHAddressHex('takerAddress', takerAddress);
|
||||
const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
|
||||
const result = await OrderValidatorContractInstance.getTraderInfo.callAsync(order, takerAddress);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get an array of objects conforming to TraderInfo containing on-chain balance and allowances for maker and taker of order
|
||||
* @param orders An array of objects conforming to SignedOrder
|
||||
* @param takerAddresses An array of ethereum addresses
|
||||
* @return array of TraderInfo
|
||||
*/
|
||||
public async getTradersInfoAsync(orders: SignedOrder[], takerAddresses: string[]): Promise<TraderInfo[]> {
|
||||
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
|
||||
_.forEach(takerAddresses, (takerAddress, index) =>
|
||||
assert.isETHAddressHex(`takerAddresses[${index}]`, takerAddress),
|
||||
);
|
||||
assert.assert(orders.length === takerAddresses.length, 'Expected orders.length to equal takerAddresses.length');
|
||||
const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
|
||||
const result = await OrderValidatorContractInstance.getTradersInfo.callAsync(orders, takerAddresses);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get an object conforming to BalanceAndAllowance containing on-chain balance and allowance for some address and assetData
|
||||
* @param address An ethereum address
|
||||
* @param assetData An encoded string that can be decoded by a specified proxy contract
|
||||
* @return BalanceAndAllowance
|
||||
*/
|
||||
public async getBalanceAndAllowanceAsync(address: string, assetData: string): Promise<BalanceAndAllowance> {
|
||||
assert.isETHAddressHex('address', address);
|
||||
assert.isHexString('assetData', assetData);
|
||||
const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
|
||||
const balanceAndAllowance = await OrderValidatorContractInstance.getBalanceAndAllowance.callAsync(
|
||||
address,
|
||||
assetData,
|
||||
);
|
||||
const result = {
|
||||
balance: balanceAndAllowance[0],
|
||||
allowance: balanceAndAllowance[1],
|
||||
};
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get an array of objects conforming to BalanceAndAllowance containing on-chain balance and allowance for some address and array of assetDatas
|
||||
* @param address An ethereum address
|
||||
* @param assetDatas An array of encoded strings that can be decoded by a specified proxy contract
|
||||
* @return BalanceAndAllowance
|
||||
*/
|
||||
public async getBalancesAndAllowancesAsync(address: string, assetDatas: string[]): Promise<BalanceAndAllowance[]> {
|
||||
assert.isETHAddressHex('address', address);
|
||||
_.forEach(assetDatas, (assetData, index) => assert.isHexString(`assetDatas[${index}]`, assetData));
|
||||
const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
|
||||
const balancesAndAllowances = await OrderValidatorContractInstance.getBalancesAndAllowances.callAsync(
|
||||
address,
|
||||
assetDatas,
|
||||
);
|
||||
const balances = balancesAndAllowances[0];
|
||||
const allowances = balancesAndAllowances[1];
|
||||
const result = _.map(balances, (balance, index) => {
|
||||
const allowance = allowances[index];
|
||||
return {
|
||||
balance,
|
||||
allowance,
|
||||
};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get owner address of tokenId by calling `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
|
||||
* @param tokenAddress An ethereum address
|
||||
* @param tokenId An ERC721 tokenId
|
||||
* @return Owner of tokenId or null address if unowned
|
||||
*/
|
||||
public async getERC721TokenOwnerAsync(tokenAddress: string, tokenId: BigNumber): Promise<string | undefined> {
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
assert.isBigNumber('tokenId', tokenId);
|
||||
const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync();
|
||||
const result = await OrderValidatorContractInstance.getERC721TokenOwner.callAsync(tokenAddress, tokenId);
|
||||
return result;
|
||||
}
|
||||
// HACK: We don't want this method to be visible to the other units within that package but not to the end user.
|
||||
// TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstance(): void {
|
||||
delete this._orderValidatorContractIfExists;
|
||||
}
|
||||
private async _getOrderValidatorContractAsync(): Promise<OrderValidatorContract> {
|
||||
if (!_.isUndefined(this._orderValidatorContractIfExists)) {
|
||||
return this._orderValidatorContractIfExists;
|
||||
}
|
||||
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(artifacts.OrderValidator);
|
||||
const contractInstance = new OrderValidatorContract(
|
||||
abi,
|
||||
address,
|
||||
this._web3Wrapper.getProvider(),
|
||||
this._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
this._orderValidatorContractIfExists = contractInstance;
|
||||
return this._orderValidatorContractIfExists;
|
||||
}
|
||||
}
|
@@ -1,8 +1,11 @@
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
import { BlockParamLiteral, ERC20TokenWrapper, ERC721TokenWrapper } from '@0xproject/contract-wrappers';
|
||||
import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0xproject/order-utils';
|
||||
import { AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { BlockParamLiteral } from 'ethereum-types';
|
||||
|
||||
import { ERC20TokenWrapper } from '../contract_wrappers/erc20_token_wrapper';
|
||||
import { ERC721TokenWrapper } from '../contract_wrappers/erc721_token_wrapper';
|
||||
|
||||
export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher {
|
||||
private readonly _erc20Token: ERC20TokenWrapper;
|
@@ -1,7 +1,10 @@
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
import { BlockParamLiteral, ExchangeWrapper } from '@0xproject/contract-wrappers';
|
||||
import { AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { BlockParamLiteral } from 'ethereum-types';
|
||||
|
||||
import { ERC20TokenWrapper } from '../contract_wrappers/erc20_token_wrapper';
|
||||
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||
|
||||
export class OrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher {
|
||||
private readonly _exchange: ExchangeWrapper;
|
@@ -6,6 +6,7 @@ export { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
|
||||
export { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
|
||||
export { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
|
||||
export { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
|
||||
export { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper';
|
||||
|
||||
export { TransactionEncoder } from './utils/transaction_encoder';
|
||||
|
||||
@@ -21,6 +22,10 @@ export {
|
||||
OrderInfo,
|
||||
EventCallback,
|
||||
DecodedLogEvent,
|
||||
BalanceAndAllowance,
|
||||
OrderAndTraderInfo,
|
||||
TraderInfo,
|
||||
ValidateOrderFillableOpts,
|
||||
} from './types';
|
||||
|
||||
export { Order, SignedOrder, AssetProxyId } from '@0xproject/types';
|
||||
@@ -81,3 +86,8 @@ export {
|
||||
ExchangeEventArgs,
|
||||
ExchangeEvents,
|
||||
} from './contract_wrappers/generated/exchange';
|
||||
|
||||
export { AbstractBalanceAndProxyAllowanceFetcher, AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils';
|
||||
|
||||
export { AssetBalanceAndProxyAllowanceFetcher } from './fetchers/asset_balance_and_proxy_allowance_fetcher';
|
||||
export { OrderFilledCancelledFetcher } from './fetchers/order_filled_cancelled_fetcher';
|
||||
|
@@ -188,3 +188,24 @@ export enum OrderStatus {
|
||||
FULLY_FILLED,
|
||||
CANCELLED,
|
||||
}
|
||||
|
||||
export interface TraderInfo {
|
||||
makerBalance: BigNumber;
|
||||
makerAllowance: BigNumber;
|
||||
takerBalance: BigNumber;
|
||||
takerAllowance: BigNumber;
|
||||
makerZrxBalance: BigNumber;
|
||||
makerZrxAllowance: BigNumber;
|
||||
takerZrxBalance: BigNumber;
|
||||
takerZrxAllowance: BigNumber;
|
||||
}
|
||||
|
||||
export interface OrderAndTraderInfo {
|
||||
orderInfo: OrderInfo;
|
||||
traderInfo: TraderInfo;
|
||||
}
|
||||
|
||||
export interface BalanceAndAllowance {
|
||||
balance: BigNumber;
|
||||
allowance: BigNumber;
|
||||
}
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -24,7 +24,7 @@ const contractCallErrorTransformer = (error: Error) => {
|
||||
const schemaErrorTransformer = (error: Error) => {
|
||||
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
|
||||
const errMsg =
|
||||
'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
||||
'Order taker must be of type string. If you want anyone to be able to fill an order - pass NULL_ADDRESS';
|
||||
return new Error(errMsg);
|
||||
}
|
||||
return error;
|
||||
|
@@ -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);
|
||||
},
|
||||
};
|
||||
|
@@ -358,7 +358,7 @@ describe('ExchangeWrapper', () => {
|
||||
describe('#getVersionAsync', () => {
|
||||
it('should return version the hash', async () => {
|
||||
const version = await contractWrappers.exchange.getVersionAsync();
|
||||
const VERSION = '2.0.1-alpha';
|
||||
const VERSION = '2.0.0';
|
||||
expect(version).to.be.equal(VERSION);
|
||||
});
|
||||
});
|
||||
|
@@ -25,10 +25,8 @@ describe('ForwarderWrapper', () => {
|
||||
blockPollingIntervalMs: 0,
|
||||
};
|
||||
const fillableAmount = new BigNumber(5);
|
||||
const takerTokenFillAmount = new BigNumber(5);
|
||||
let contractWrappers: ContractWrappers;
|
||||
let fillScenarios: FillScenarios;
|
||||
let forwarderContractAddress: string;
|
||||
let exchangeContractAddress: string;
|
||||
let zrxTokenAddress: string;
|
||||
let userAddresses: string[];
|
||||
@@ -46,7 +44,6 @@ describe('ForwarderWrapper', () => {
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
contractWrappers = new ContractWrappers(provider, contractWrappersConfig);
|
||||
forwarderContractAddress = contractWrappers.forwarder.getContractAddress();
|
||||
exchangeContractAddress = contractWrappers.exchange.getContractAddress();
|
||||
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
zrxTokenAddress = tokenUtils.getProtocolTokenAddress();
|
||||
|
142
packages/contract-wrappers/test/order_validator_wrapper_test.ts
Normal file
142
packages/contract-wrappers/test/order_validator_wrapper_test.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { FillScenarios } from '@0xproject/fill-scenarios';
|
||||
import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
|
||||
import { DoneCallback, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import { BlockParamLiteral } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
|
||||
import { ContractWrappers, ExchangeCancelEventArgs, ExchangeEvents, ExchangeFillEventArgs, OrderStatus } from '../src';
|
||||
import { DecodedLogEvent, OrderInfo, TraderInfo } from '../src/types';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
import { tokenUtils } from './utils/token_utils';
|
||||
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('OrderValidator', () => {
|
||||
const contractWrappersConfig = {
|
||||
networkId: constants.TESTRPC_NETWORK_ID,
|
||||
blockPollingIntervalMs: 0,
|
||||
};
|
||||
const fillableAmount = new BigNumber(5);
|
||||
const partialFillAmount = new BigNumber(2);
|
||||
let contractWrappers: ContractWrappers;
|
||||
let fillScenarios: FillScenarios;
|
||||
let exchangeContractAddress: string;
|
||||
let zrxTokenAddress: string;
|
||||
let zrxTokenAssetData: string;
|
||||
let userAddresses: string[];
|
||||
let coinbase: string;
|
||||
let makerAddress: string;
|
||||
let takerAddress: string;
|
||||
let feeRecipient: string;
|
||||
let anotherMakerAddress: string;
|
||||
let makerTokenAddress: string;
|
||||
let takerTokenAddress: string;
|
||||
let makerAssetData: string;
|
||||
let takerAssetData: string;
|
||||
let signedOrder: SignedOrder;
|
||||
let anotherSignedOrder: SignedOrder;
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
contractWrappers = new ContractWrappers(provider, contractWrappersConfig);
|
||||
exchangeContractAddress = contractWrappers.exchange.getContractAddress();
|
||||
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
zrxTokenAddress = tokenUtils.getProtocolTokenAddress();
|
||||
zrxTokenAssetData = assetDataUtils.encodeERC20AssetData(zrxTokenAddress);
|
||||
fillScenarios = new FillScenarios(
|
||||
provider,
|
||||
userAddresses,
|
||||
zrxTokenAddress,
|
||||
exchangeContractAddress,
|
||||
contractWrappers.erc20Proxy.getContractAddress(),
|
||||
contractWrappers.erc721Proxy.getContractAddress(),
|
||||
);
|
||||
[coinbase, makerAddress, takerAddress, feeRecipient, anotherMakerAddress] = userAddresses;
|
||||
[makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
|
||||
takerTokenAddress = tokenUtils.getWethTokenAddress();
|
||||
[makerAssetData, takerAssetData] = [
|
||||
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
|
||||
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
|
||||
];
|
||||
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerAssetData,
|
||||
takerAssetData,
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
fillableAmount,
|
||||
);
|
||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
zrxTokenAssetData,
|
||||
takerAssetData,
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('#getOrdersAndTradersInfoAsync', () => {
|
||||
let signedOrders: SignedOrder[];
|
||||
let takerAddresses: string[];
|
||||
let ordersInfo: OrderInfo[];
|
||||
let tradersInfo: TraderInfo[];
|
||||
beforeEach(async () => {
|
||||
signedOrders = [signedOrder, anotherSignedOrder];
|
||||
takerAddresses = [takerAddress, takerAddress];
|
||||
const ordersAndTradersInfo = await contractWrappers.orderValidator.getOrdersAndTradersInfoAsync(
|
||||
signedOrders,
|
||||
takerAddresses,
|
||||
);
|
||||
ordersInfo = _.map(ordersAndTradersInfo, orderAndTraderInfo => orderAndTraderInfo.orderInfo);
|
||||
tradersInfo = _.map(ordersAndTradersInfo, orderAndTraderInfo => orderAndTraderInfo.traderInfo);
|
||||
});
|
||||
it('should return the same number of order infos and trader infos as input orders', async () => {
|
||||
expect(ordersInfo.length).to.be.equal(signedOrders.length);
|
||||
expect(tradersInfo.length).to.be.equal(takerAddresses.length);
|
||||
});
|
||||
it('should return correct on-chain order info for input orders', async () => {
|
||||
const firstOrderInfo = ordersInfo[0];
|
||||
const secondOrderInfo = ordersInfo[1];
|
||||
expect(firstOrderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
expect(firstOrderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||
expect(secondOrderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
expect(secondOrderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||
});
|
||||
it('should return correct on-chain trader info for input takers', async () => {
|
||||
const firstTraderInfo = tradersInfo[0];
|
||||
const secondTraderInfo = tradersInfo[1];
|
||||
expect(firstTraderInfo.makerBalance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(firstTraderInfo.makerAllowance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(firstTraderInfo.takerBalance).to.bignumber.equal(new BigNumber(0));
|
||||
expect(firstTraderInfo.takerAllowance).to.bignumber.equal(new BigNumber(0));
|
||||
expect(firstTraderInfo.makerZrxBalance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(firstTraderInfo.makerZrxAllowance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(firstTraderInfo.takerZrxBalance).to.bignumber.equal(new BigNumber(0));
|
||||
expect(firstTraderInfo.takerZrxAllowance).to.bignumber.equal(new BigNumber(0));
|
||||
expect(secondTraderInfo.makerBalance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(secondTraderInfo.makerAllowance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(secondTraderInfo.takerBalance).to.bignumber.equal(new BigNumber(0));
|
||||
expect(secondTraderInfo.takerAllowance).to.bignumber.equal(new BigNumber(0));
|
||||
expect(secondTraderInfo.makerZrxBalance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(secondTraderInfo.makerZrxAllowance).to.bignumber.equal(new BigNumber(5));
|
||||
expect(secondTraderInfo.takerZrxBalance).to.bignumber.equal(new BigNumber(0));
|
||||
expect(secondTraderInfo.takerZrxAllowance).to.bignumber.equal(new BigNumber(0));
|
||||
});
|
||||
});
|
||||
});
|
@@ -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'),
|
||||
),
|
||||
];
|
||||
|
@@ -15,4 +15,5 @@ export const constants = {
|
||||
DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(10 ** 27), // tslint:disable-line:custom-no-magic-numbers
|
||||
NUM_DUMMY_ERC20_TO_DEPLOY: 3,
|
||||
NUM_DUMMY_ERC721_TO_DEPLOY: 1,
|
||||
ZERO_AMOUNT: new BigNumber(0),
|
||||
};
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
||||
|
7
packages/contract-wrappers/typedoc-tsconfig.json
Normal file
7
packages/contract-wrappers/typedoc-tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../typedoc-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
@@ -1,14 +1,35 @@
|
||||
## Contracts
|
||||
|
||||
Smart contracts that implement the 0x protocol.
|
||||
Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found [here](https://0xproject.com/wiki#Deployed-Addresses).
|
||||
|
||||
## Usage
|
||||
|
||||
* [Docs](https://0xproject.com/docs/contracts)
|
||||
* [Overview of 0x protocol architecture](https://0xproject.com/wiki#Architecture)
|
||||
* [0x smart contract interactions](https://0xproject.com/wiki#Contract-Interactions)
|
||||
* [Deployed smart contract addresses](https://0xproject.com/wiki#Deployed-Addresses)
|
||||
* [0x protocol message format](https://0xproject.com/wiki#Message-Format)
|
||||
### 2.0.0
|
||||
|
||||
Contracts that make up and interact with version 2.0.0 of the protocol can be found in the `src/2.0.0` directory. The contents of this directory are broken down into the following subdirectories:
|
||||
|
||||
* protocol
|
||||
* This directory contains the contracts that make up version 2.0.0. A full specification can be found [here](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
|
||||
* extensions
|
||||
* This directory contains contracts that interact with the 2.0.0 contracts and will be used in production, such as the [Forwarder](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract.
|
||||
* examples
|
||||
* This directory contains example implementations of contracts that interact with the protocol but are _not_ intended for use in production. Examples include [filter](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#filter-contracts) contracts, a [Wallet](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#wallet) contract, and a [Validator](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#validator) contract, among others.
|
||||
* tokens
|
||||
* This directory contains implementations of different tokens and token standards, including [wETH](https://weth.io/), ZRX, [ERC20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md), and [ERC721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md).
|
||||
* multisig
|
||||
* This directory contains the [Gnosis MultiSigWallet](https://github.com/gnosis/MultiSigWallet) and a custom extension that adds a timelock to transactions within the MultiSigWallet.
|
||||
* utils
|
||||
* This directory contains libraries and utils that are shared across all of the other directories.
|
||||
* test
|
||||
* This directory contains mocks and other contracts that are used solely for testing contracts within the other directories.
|
||||
|
||||
### 1.0.0
|
||||
|
||||
Contracts that make up version 1.0.0 of the protocol can be found in `src/1.0.0`. These contracts are considered deprecated and will have limited support going forward.
|
||||
|
||||
## Bug bounty
|
||||
|
||||
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"artifactsDir": "../migrations/artifacts/2.0.0",
|
||||
"artifactsDir": "../migrations/artifacts/development",
|
||||
"contractsDir": "src/",
|
||||
"compilerSettings": {
|
||||
"optimizer": {
|
||||
@@ -23,6 +23,7 @@
|
||||
"DummyERC20Token",
|
||||
"DummyERC721Receiver",
|
||||
"DummyERC721Token",
|
||||
"DummyMultipleReturnERC20Token",
|
||||
"DummyNoReturnERC20Token",
|
||||
"ERC20Proxy",
|
||||
"ERC20Token",
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "contracts",
|
||||
"version": "2.1.42",
|
||||
"version": "2.1.47",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -11,10 +11,9 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && tsc",
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"pre_build": "run-s compile copy_artifacts generate_contract_wrappers",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/2.0.0/**/*' ./lib/artifacts;",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/development/**/*' ./lib/artifacts;",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
@@ -33,7 +32,7 @@
|
||||
"lint-contracts": "solhint src/2.0.0/**/**/**/**/*.sol"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
"abis": "../migrations/artifacts/development/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -46,16 +45,16 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.7",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/sol-compiler": "^1.1.1",
|
||||
"@0xproject/sol-cov": "^2.1.1",
|
||||
"@0xproject/subproviders": "^2.0.1",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/node": "*",
|
||||
"@types/yargs": "^10.0.0",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
@@ -73,15 +72,15 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/base-contract": "^2.0.1",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.6",
|
||||
"@0xproject/types": "^1.0.1-rc.6",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@0xproject/web3-wrapper": "^2.0.1",
|
||||
"@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.5",
|
||||
"ethereum-types": "^1.0.8",
|
||||
"ethereumjs-abi": "0.6.5",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "3.0.22",
|
||||
|
@@ -34,7 +34,6 @@ contract Forwarder is
|
||||
MixinExchangeWrapper,
|
||||
MixinForwarderCore
|
||||
{
|
||||
|
||||
constructor (
|
||||
address _exchange,
|
||||
bytes memory _zrxAssetData,
|
||||
|
@@ -31,7 +31,6 @@ contract MixinAssets is
|
||||
LibConstants,
|
||||
MAssets
|
||||
{
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
|
||||
|
@@ -34,7 +34,6 @@ contract MixinExchangeWrapper is
|
||||
LibConstants,
|
||||
MExchangeWrapper
|
||||
{
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
@@ -61,7 +60,7 @@ contract MixinExchangeWrapper is
|
||||
// Call `fillOrder` and handle any exceptions gracefully
|
||||
assembly {
|
||||
let success := call(
|
||||
gas, // forward all gas, TODO: look into gas consumption of assert/throw
|
||||
gas, // forward all gas
|
||||
exchange, // call address of Exchange contract
|
||||
0, // transfer 0 wei
|
||||
add(fillOrderCalldata, 32), // pointer to start of input (skip array length in first 32 bytes)
|
||||
@@ -69,20 +68,14 @@ contract MixinExchangeWrapper is
|
||||
fillOrderCalldata, // write output over input
|
||||
128 // output size is 128 bytes
|
||||
)
|
||||
switch success
|
||||
case 0 {
|
||||
mstore(fillResults, 0)
|
||||
mstore(add(fillResults, 32), 0)
|
||||
mstore(add(fillResults, 64), 0)
|
||||
mstore(add(fillResults, 96), 0)
|
||||
}
|
||||
case 1 {
|
||||
if success {
|
||||
mstore(fillResults, mload(fillOrderCalldata))
|
||||
mstore(add(fillResults, 32), mload(add(fillOrderCalldata, 32)))
|
||||
mstore(add(fillResults, 64), mload(add(fillOrderCalldata, 64)))
|
||||
mstore(add(fillResults, 96), mload(add(fillOrderCalldata, 96)))
|
||||
}
|
||||
}
|
||||
// fillResults values will be 0 by default if call was unsuccessful
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
|
@@ -39,7 +39,6 @@ contract MixinForwarderCore is
|
||||
MExchangeWrapper,
|
||||
IForwarderCore
|
||||
{
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
/// @dev Constructor approves ERC20 proxy to transfer ZRX and WETH on this contract's behalf.
|
||||
@@ -47,10 +46,12 @@ contract MixinForwarderCore is
|
||||
public
|
||||
{
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
|
||||
if (proxyAddress != address(0)) {
|
||||
ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
|
||||
ZRX_TOKEN.approve(proxyAddress, MAX_UINT);
|
||||
}
|
||||
require(
|
||||
proxyAddress != address(0),
|
||||
"UNREGISTERED_ASSET_PROXY"
|
||||
);
|
||||
ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
|
||||
ZRX_TOKEN.approve(proxyAddress, MAX_UINT);
|
||||
}
|
||||
|
||||
/// @dev Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
|
||||
|
@@ -28,7 +28,6 @@ contract MixinWeth is
|
||||
LibConstants,
|
||||
MWeth
|
||||
{
|
||||
|
||||
/// @dev Default payabale function, this allows us to withdraw WETH
|
||||
function ()
|
||||
public
|
||||
|
@@ -24,7 +24,6 @@ import "../interfaces/IAssets.sol";
|
||||
contract MAssets is
|
||||
IAssets
|
||||
{
|
||||
|
||||
/// @dev Transfers given amount of asset to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
|
@@ -28,11 +28,11 @@ import "../../utils/LibBytes/LibBytes.sol";
|
||||
|
||||
contract OrderValidator {
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||
bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
struct TraderInfo {
|
||||
uint256 makerBalance; // Maker's balance of makerAsset
|
||||
uint256 makerAllowance; // Maker's allowance to corresponding AssetProxy
|
||||
|
@@ -1,13 +1,14 @@
|
||||
// solhint-disable
|
||||
pragma solidity ^0.4.10;
|
||||
pragma solidity ^0.4.15;
|
||||
|
||||
|
||||
/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
|
||||
/// @author Stefan George - <stefan.george@consensys.net>
|
||||
contract MultiSigWallet {
|
||||
|
||||
uint constant public MAX_OWNER_COUNT = 50;
|
||||
|
||||
/*
|
||||
* Events
|
||||
*/
|
||||
event Confirmation(address indexed sender, uint indexed transactionId);
|
||||
event Revocation(address indexed sender, uint indexed transactionId);
|
||||
event Submission(uint indexed transactionId);
|
||||
@@ -18,6 +19,14 @@ contract MultiSigWallet {
|
||||
event OwnerRemoval(address indexed owner);
|
||||
event RequirementChange(uint required);
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
uint constant public MAX_OWNER_COUNT = 50;
|
||||
|
||||
/*
|
||||
* Storage
|
||||
*/
|
||||
mapping (uint => Transaction) public transactions;
|
||||
mapping (uint => mapping (address => bool)) public confirmations;
|
||||
mapping (address => bool) public isOwner;
|
||||
@@ -32,60 +41,54 @@ contract MultiSigWallet {
|
||||
bool executed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modifiers
|
||||
*/
|
||||
modifier onlyWallet() {
|
||||
if (msg.sender != address(this))
|
||||
throw;
|
||||
require(msg.sender == address(this));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier ownerDoesNotExist(address owner) {
|
||||
if (isOwner[owner])
|
||||
throw;
|
||||
require(!isOwner[owner]);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier ownerExists(address owner) {
|
||||
if (!isOwner[owner])
|
||||
throw;
|
||||
require(isOwner[owner]);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier transactionExists(uint transactionId) {
|
||||
if (transactions[transactionId].destination == 0)
|
||||
throw;
|
||||
require(transactions[transactionId].destination != 0);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier confirmed(uint transactionId, address owner) {
|
||||
if (!confirmations[transactionId][owner])
|
||||
throw;
|
||||
require(confirmations[transactionId][owner]);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notConfirmed(uint transactionId, address owner) {
|
||||
if (confirmations[transactionId][owner])
|
||||
throw;
|
||||
require(!confirmations[transactionId][owner]);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notExecuted(uint transactionId) {
|
||||
if (transactions[transactionId].executed)
|
||||
throw;
|
||||
require(!transactions[transactionId].executed);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notNull(address _address) {
|
||||
if (_address == 0)
|
||||
throw;
|
||||
require(_address != 0);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier validRequirement(uint ownerCount, uint _required) {
|
||||
if ( ownerCount > MAX_OWNER_COUNT
|
||||
|| _required > ownerCount
|
||||
|| _required == 0
|
||||
|| ownerCount == 0)
|
||||
throw;
|
||||
require(ownerCount <= MAX_OWNER_COUNT
|
||||
&& _required <= ownerCount
|
||||
&& _required != 0
|
||||
&& ownerCount != 0);
|
||||
_;
|
||||
}
|
||||
|
||||
@@ -108,8 +111,7 @@ contract MultiSigWallet {
|
||||
validRequirement(_owners.length, _required)
|
||||
{
|
||||
for (uint i=0; i<_owners.length; i++) {
|
||||
if (isOwner[_owners[i]] || _owners[i] == 0)
|
||||
throw;
|
||||
require(!isOwner[_owners[i]] && _owners[i] != 0);
|
||||
isOwner[_owners[i]] = true;
|
||||
}
|
||||
owners = _owners;
|
||||
@@ -151,7 +153,7 @@ contract MultiSigWallet {
|
||||
|
||||
/// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
|
||||
/// @param owner Address of owner to be replaced.
|
||||
/// @param owner Address of new owner.
|
||||
/// @param newOwner Address of new owner.
|
||||
function replaceOwner(address owner, address newOwner)
|
||||
public
|
||||
onlyWallet
|
||||
@@ -222,20 +224,44 @@ contract MultiSigWallet {
|
||||
/// @param transactionId Transaction ID.
|
||||
function executeTransaction(uint transactionId)
|
||||
public
|
||||
ownerExists(msg.sender)
|
||||
confirmed(transactionId, msg.sender)
|
||||
notExecuted(transactionId)
|
||||
{
|
||||
if (isConfirmed(transactionId)) {
|
||||
Transaction tx = transactions[transactionId];
|
||||
tx.executed = true;
|
||||
if (tx.destination.call.value(tx.value)(tx.data))
|
||||
Transaction storage txn = transactions[transactionId];
|
||||
txn.executed = true;
|
||||
if (external_call(txn.destination, txn.value, txn.data.length, txn.data))
|
||||
Execution(transactionId);
|
||||
else {
|
||||
ExecutionFailure(transactionId);
|
||||
tx.executed = false;
|
||||
txn.executed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call has been separated into its own function in order to take advantage
|
||||
// of the Solidity's code generator to produce a loop that copies tx.data into memory.
|
||||
function external_call(address destination, uint value, uint dataLength, bytes data) internal returns (bool) {
|
||||
bool result;
|
||||
assembly {
|
||||
let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
|
||||
let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that
|
||||
result := call(
|
||||
sub(gas, 34710), // 34710 is the value that solidity is currently emitting
|
||||
// It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +
|
||||
// callNewAccountGas (25000, in case the destination address does not exist and needs creating)
|
||||
destination,
|
||||
value,
|
||||
d,
|
||||
dataLength, // Size of the input (in bytes) - this is what fixes the padding problem
|
||||
x,
|
||||
0 // Output is ignored, therefore the output size is zero
|
||||
)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Returns the confirmation status of a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
/// @return Confirmation status.
|
||||
@@ -364,4 +390,4 @@ contract MultiSigWallet {
|
||||
for (i=from; i<to; i++)
|
||||
_transactionIds[i - from] = transactionIdsTemp[i];
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,47 +16,57 @@
|
||||
|
||||
*/
|
||||
|
||||
// solhint-disable
|
||||
pragma solidity ^0.4.10;
|
||||
pragma solidity 0.4.24;
|
||||
|
||||
import "./MultiSigWallet.sol";
|
||||
|
||||
|
||||
/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>
|
||||
contract MultiSigWalletWithTimeLock is MultiSigWallet {
|
||||
// solhint-disable not-rely-on-time
|
||||
contract MultiSigWalletWithTimeLock is
|
||||
MultiSigWallet
|
||||
{
|
||||
event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime);
|
||||
event TimeLockChange(uint256 secondsTimeLocked);
|
||||
|
||||
event ConfirmationTimeSet(uint indexed transactionId, uint confirmationTime);
|
||||
event TimeLockChange(uint secondsTimeLocked);
|
||||
uint256 public secondsTimeLocked;
|
||||
|
||||
uint public secondsTimeLocked;
|
||||
mapping (uint256 => uint256) public confirmationTimes;
|
||||
|
||||
mapping (uint => uint) public confirmationTimes;
|
||||
|
||||
modifier notFullyConfirmed(uint transactionId) {
|
||||
require(!isConfirmed(transactionId));
|
||||
modifier notFullyConfirmed(uint256 transactionId) {
|
||||
require(
|
||||
!isConfirmed(transactionId),
|
||||
"TX_FULLY_CONFIRMED"
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier fullyConfirmed(uint transactionId) {
|
||||
require(isConfirmed(transactionId));
|
||||
modifier fullyConfirmed(uint256 transactionId) {
|
||||
require(
|
||||
isConfirmed(transactionId),
|
||||
"TX_NOT_FULLY_CONFIRMED"
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier pastTimeLock(uint transactionId) {
|
||||
require(block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked);
|
||||
modifier pastTimeLock(uint256 transactionId) {
|
||||
require(
|
||||
block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked,
|
||||
"TIME_LOCK_INCOMPLETE"
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/// @dev Contract constructor sets initial owners, required number of confirmations, and time lock.
|
||||
/// @param _owners List of initial owners.
|
||||
/// @param _required Number of required confirmations.
|
||||
/// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
|
||||
function MultiSigWalletWithTimeLock(address[] _owners, uint _required, uint _secondsTimeLocked)
|
||||
constructor (
|
||||
address[] _owners,
|
||||
uint256 _required,
|
||||
uint256 _secondsTimeLocked
|
||||
)
|
||||
public
|
||||
MultiSigWallet(_owners, _required)
|
||||
{
|
||||
@@ -65,17 +75,17 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet {
|
||||
|
||||
/// @dev Changes the duration of the time lock for transactions.
|
||||
/// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
|
||||
function changeTimeLock(uint _secondsTimeLocked)
|
||||
function changeTimeLock(uint256 _secondsTimeLocked)
|
||||
public
|
||||
onlyWallet
|
||||
{
|
||||
secondsTimeLocked = _secondsTimeLocked;
|
||||
TimeLockChange(_secondsTimeLocked);
|
||||
emit TimeLockChange(_secondsTimeLocked);
|
||||
}
|
||||
|
||||
/// @dev Allows an owner to confirm a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function confirmTransaction(uint transactionId)
|
||||
function confirmTransaction(uint256 transactionId)
|
||||
public
|
||||
ownerExists(msg.sender)
|
||||
transactionExists(transactionId)
|
||||
@@ -83,52 +93,35 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet {
|
||||
notFullyConfirmed(transactionId)
|
||||
{
|
||||
confirmations[transactionId][msg.sender] = true;
|
||||
Confirmation(msg.sender, transactionId);
|
||||
emit Confirmation(msg.sender, transactionId);
|
||||
if (isConfirmed(transactionId)) {
|
||||
setConfirmationTime(transactionId, block.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Allows an owner to revoke a confirmation for a transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function revokeConfirmation(uint transactionId)
|
||||
public
|
||||
ownerExists(msg.sender)
|
||||
confirmed(transactionId, msg.sender)
|
||||
notExecuted(transactionId)
|
||||
notFullyConfirmed(transactionId)
|
||||
{
|
||||
confirmations[transactionId][msg.sender] = false;
|
||||
Revocation(msg.sender, transactionId);
|
||||
}
|
||||
|
||||
/// @dev Allows anyone to execute a confirmed transaction.
|
||||
/// @param transactionId Transaction ID.
|
||||
function executeTransaction(uint transactionId)
|
||||
function executeTransaction(uint256 transactionId)
|
||||
public
|
||||
notExecuted(transactionId)
|
||||
fullyConfirmed(transactionId)
|
||||
pastTimeLock(transactionId)
|
||||
{
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
tx.executed = true;
|
||||
if (tx.destination.call.value(tx.value)(tx.data))
|
||||
Execution(transactionId);
|
||||
else {
|
||||
ExecutionFailure(transactionId);
|
||||
tx.executed = false;
|
||||
Transaction storage txn = transactions[transactionId];
|
||||
txn.executed = true;
|
||||
if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) {
|
||||
emit Execution(transactionId);
|
||||
} else {
|
||||
emit ExecutionFailure(transactionId);
|
||||
txn.executed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal functions
|
||||
*/
|
||||
|
||||
/// @dev Sets the time of when a submission first passed.
|
||||
function setConfirmationTime(uint transactionId, uint confirmationTime)
|
||||
function setConfirmationTime(uint256 transactionId, uint256 confirmationTime)
|
||||
internal
|
||||
{
|
||||
confirmationTimes[transactionId] = confirmationTime;
|
||||
ConfirmationTimeSet(transactionId, confirmationTime);
|
||||
emit ConfirmationTimeSet(transactionId, confirmationTime);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user