Merge branch 'development' into dev-dropdown
* development: (120 commits) Exit with non-error code at end of publishRelease Publish Updated CHANGELOGS Fix prettier Update changelog files for RC packages Skip doc generation for local publishes since we test this in a separate CI test Fix typo Use absolute path Run yarn a second time if the first fails Try relative to root dir Fix command Move md files to lib folder during build Change exit code to failure Fix sra-spec `main` and `types` in package.json Actual relative path Try relative path Issue #1025 BlockParam unroll Fix command Move md files to lib folder during build Fix sra-spec `main` and `types` in package.json ...
This commit is contained in:
commit
b8241c0f80
@ -18,11 +18,11 @@ jobs:
|
||||
- yarn-packages-master
|
||||
- yarn-packages-
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile install || true
|
||||
name: install-yarn
|
||||
command: sudo npm install --global yarn@1.9.4
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile install
|
||||
command: yarn --frozen-lockfile install || yarn --frozen-lockfile install
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
|
@ -15,7 +15,7 @@ lib
|
||||
/packages/contract-wrappers/src/artifacts
|
||||
/packages/order-watcher/src/artifacts
|
||||
/packages/metacoin/artifacts
|
||||
/packages/sra-api/public/
|
||||
/packages/sra-spec/public/
|
||||
/packages/contract-wrappers/test/artifacts
|
||||
/packages/order-watcher/test/artifacts
|
||||
/packages/migrations/artifacts/1.0.0
|
||||
|
@ -33,7 +33,7 @@ If you're developing on 0x now or are interested in using 0x infrastructure in t
|
||||
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | [](https://www.npmjs.com/package/@0xproject/monorepo-scripts) | Monorepo scripts |
|
||||
| [`@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/sra-api`](/packages/sra-api) | [](https://www.npmjs.com/package/@0xproject/sra-api) | OpenAPI specification for the standard relayer API |
|
||||
| [`@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) |
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.1-rc.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix missing `BlockParamLiteral` type import issue"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
{
|
||||
"note":
|
||||
"Fix `main` and `types` package.json entries so that they point to the new location of index.d.ts and index.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.4",
|
||||
"changes": [
|
||||
@ -7,7 +25,8 @@
|
||||
"Re-organize the exported interface of 0x.js. Remove the `ZeroEx` class, and instead export the same exports as `0x.js`'s sub-packages: `@0xproject/contract-wrappers`, `@0xproject/order-utils` and `@0xproject/order-watcher`",
|
||||
"pr": 963
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.3",
|
||||
|
@ -5,7 +5,19 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.3 - _August 13, 2018_
|
||||
## v1.0.1-rc.6 - _August 27, 2018_
|
||||
|
||||
* Fix missing `BlockParamLiteral` type import issue
|
||||
|
||||
## v1.0.1-rc.5 - _Invalid date_
|
||||
|
||||
* Fix `main` and `types` package.json entries so that they point to the new location of index.d.ts and index.js
|
||||
|
||||
## v1.0.1-rc.4 - _August 24, 2018_
|
||||
|
||||
* Re-organize the exported interface of 0x.js. Remove the `ZeroEx` class, and instead export the same exports as `0x.js`'s sub-packages: `@0xproject/contract-wrappers`, `@0xproject/order-utils` and `@0xproject/order-watcher` (#963)
|
||||
|
||||
## v1.0.1-rc.3 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
* Update ecSignOrderHashAsync to return the signature as a string for immediate use in contracts (#914)
|
||||
@ -22,11 +34,11 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-rc.2 - _July 19, 2018_
|
||||
## v1.0.0-rc.2 - _July 20, 2018_
|
||||
|
||||
* Remove `zeroEx.assetData` and instead re-export it's static functions directly off `ZeroEx`
|
||||
|
||||
## v1.0.0-rc.1 - _July 19, 2018_
|
||||
## v1.0.0-rc.1 - _July 20, 2018_
|
||||
|
||||
* Remove tokenRegistry wrapper (#863)
|
||||
* Rename `zeroEx.token` to `zeroEx.erc20Token`, and add `zeroEx.erc721Token` (#863)
|
||||
@ -66,7 +78,7 @@ CHANGELOG
|
||||
* Renamed createOrderStateWatcher to createOrderWatcherAsync since it is now async (#579)
|
||||
* Renamed ZeroExError to ContractWrappersErrors since they now lives in the @0xproject/contract-wrappers subpackage (#579)
|
||||
|
||||
## v0.37.2 - _May 4, 2018_
|
||||
## v0.37.2 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "0x.js",
|
||||
"version": "1.0.1-rc.3",
|
||||
"version": "1.0.1-rc.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -12,15 +12,14 @@
|
||||
"tokens",
|
||||
"exchange"
|
||||
],
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"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/**/*",
|
||||
"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",
|
||||
@ -43,11 +42,11 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/migrations": "^1.0.4",
|
||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/node": "^8.0.53",
|
||||
@ -74,17 +73,17 @@
|
||||
"webpack": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.5",
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/contract-wrappers": "^1.0.1-rc.3",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.3",
|
||||
"@0xproject/order-watcher": "1.0.1-rc.3",
|
||||
"@0xproject/subproviders": "^1.0.5",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"@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",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.5",
|
||||
"web3-provider-engine": "14.0.6"
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "1.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535133899,
|
||||
"version": "1.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1534210131,
|
||||
"version": "1.0.5",
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.5 - _August 13, 2018_
|
||||
## v1.0.7 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.6 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.5 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -25,7 +33,7 @@ CHANGELOG
|
||||
|
||||
* Fix the abi-gen entry point in package.json (#901)
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Convert e_r_c to erc in generated file names (#822)
|
||||
* Remove the output directory before writing to it (#822)
|
||||
@ -43,7 +51,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.3.1 - _May 31, 2018_
|
||||
## v0.3.1 - _June 1, 2018_
|
||||
|
||||
* Incorrect publish that was unpublished
|
||||
|
||||
@ -51,7 +59,7 @@ CHANGELOG
|
||||
|
||||
* Properly export the executable binary (#588)
|
||||
|
||||
## v0.2.13 - _May 4, 2018_
|
||||
## v0.2.13 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/abi-gen",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.7",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -31,10 +31,10 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"chalk": "^2.3.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"glob": "^7.1.2",
|
||||
"handlebars": "^4.0.11",
|
||||
"lodash": "^4.17.5",
|
||||
@ -45,7 +45,7 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/glob": "5.0.35",
|
||||
"@types/handlebars": "^4.0.36",
|
||||
"@types/mkdirp": "^0.5.1",
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "1.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535133899,
|
||||
"version": "1.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1534210131,
|
||||
"version": "1.0.5",
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.5 - _August 13, 2018_
|
||||
## v1.0.7 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.6 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.5 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -25,7 +33,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Fix bug in string enum assertion. We erroneously were checking against the enum keys, not values (#821)
|
||||
|
||||
@ -41,7 +49,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.2.11 - _May 31, 2018_
|
||||
## v0.2.11 - _June 1, 2018_
|
||||
|
||||
* Incorrect publish that was unpublished
|
||||
|
||||
@ -49,7 +57,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.2.9 - _May 4, 2018_
|
||||
## v0.2.9 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/assert",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.7",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -29,7 +29,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/valid-url": "^1.0.2",
|
||||
@ -45,9 +45,9 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.6",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"lodash": "^4.17.5",
|
||||
"valid-url": "^1.0.9"
|
||||
},
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "2.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535133899,
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.0-rc.1",
|
||||
"changes": [
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.0-rc.1 - _August 13, 2018_
|
||||
## v2.0.1 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.0 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.0-rc.1 - _August 14, 2018_
|
||||
|
||||
* Added strict encoding/decoding checks for sendTransaction and call (#915)
|
||||
|
||||
@ -25,7 +33,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -41,7 +49,7 @@ CHANGELOG
|
||||
|
||||
* Update EthersJs to fix the `value.toLowerCase()` is not a function bug caused by `ethers.js` breaking patch version https://github.com/ethers-io/ethers.js/issues/201
|
||||
|
||||
## v0.3.3 - _May 31, 2018_
|
||||
## v0.3.3 - _June 1, 2018_
|
||||
|
||||
* Incorrect publish that was unpublished
|
||||
|
||||
@ -49,7 +57,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.3.1 - _May 4, 2018_
|
||||
## v0.3.1 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/base-contract",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -29,7 +29,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/lodash": "4.14.104",
|
||||
"chai": "^4.0.1",
|
||||
"copyfiles": "^2.0.0",
|
||||
@ -41,10 +41,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@0xproject/web3-wrapper": "^2.0.1",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.5"
|
||||
},
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "2.0.0-rc.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "2.0.0-rc.1",
|
||||
"changes": [
|
||||
@ -10,7 +19,8 @@
|
||||
"note": "Stopped exporting `Order` type",
|
||||
"pr": 924
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"timestamp": 1534210131,
|
||||
|
@ -5,7 +5,16 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.5 - _August 13, 2018_
|
||||
## v2.0.0-rc.2 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.0-rc.1 - _August 24, 2018_
|
||||
|
||||
* Updated for SRA v2 (#974)
|
||||
* Stopped exporting `Order` type (#924)
|
||||
|
||||
## v1.0.5 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -25,7 +34,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Remove `WebSocketOrderbookChannel` from the public interface and replace with `orderbookChannelFactory`
|
||||
|
||||
@ -49,7 +58,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.6.12 - _May 4, 2018_
|
||||
## v0.6.12 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/connect",
|
||||
"version": "1.0.5",
|
||||
"version": "2.0.0-rc.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -44,11 +44,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.5",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.4",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@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",
|
||||
"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.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/fetch-mock": "^6.0.3",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix missing `BlockParamLiteral` type import issue"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.4",
|
||||
"changes": [
|
||||
@ -16,7 +25,8 @@
|
||||
"note": "Added Transaction Encoder for use with 0x Exchange executeTransaction",
|
||||
"pr": 975
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.3",
|
||||
|
@ -5,7 +5,17 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.3 - _August 13, 2018_
|
||||
## v1.0.1-rc.5 - _August 27, 2018_
|
||||
|
||||
* Fix missing `BlockParamLiteral` type import issue
|
||||
|
||||
## v1.0.1-rc.4 - _August 24, 2018_
|
||||
|
||||
* Export missing types: `TransactionEncoder`, `ContractAbi`, `JSONRPCRequestPayload`, `JSONRPCResponsePayload`, `JSONRPCErrorCallback`, `AbiDefinition`, `FunctionAbi`, `EventAbi`, `EventParameter`, `DecodedLogArgs`, `MethodAbi`, `ConstructorAbi`, `FallbackAbi`, `DataItem`, `ConstructorStateMutability`, `StateMutability` & `ExchangeSignatureValidatorApprovalEventArgs` (#924)
|
||||
* Remove superfluous exported types: `ContractEvent`, `Token`, `OrderFillRequest`, `ContractEventArgs`, `LogEvent`, `OnOrderStateChangeCallback`, `ECSignature`, `OrderStateValid`, `OrderStateInvalid`, `OrderState`, `FilterObject`, `TransactionReceipt` & `TransactionReceiptWithDecodedLogs` (#924)
|
||||
* Added Transaction Encoder for use with 0x Exchange executeTransaction (#975)
|
||||
|
||||
## v1.0.1-rc.3 - _August 14, 2018_
|
||||
|
||||
* Added strict encoding/decoding checks for sendTransaction and call (#915)
|
||||
* Add ForwarderWrapper (#934)
|
||||
@ -23,7 +33,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-rc.1 - _July 19, 2018_
|
||||
## v1.0.0-rc.1 - _July 20, 2018_
|
||||
|
||||
* Update blockstream to v5.0 and propogate up caught errors to active subscriptions (#815)
|
||||
* Update to v2 of 0x rpotocol (#822)
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/contract-wrappers",
|
||||
"version": "1.0.1-rc.3",
|
||||
"version": "1.0.1-rc.5",
|
||||
"description": "Smart TS wrappers for 0x smart contracts",
|
||||
"keywords": [
|
||||
"0xproject",
|
||||
@ -44,11 +44,11 @@
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/migrations": "^1.0.4",
|
||||
"@0xproject/subproviders": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/node": "^8.0.53",
|
||||
@ -74,16 +74,16 @@
|
||||
"web3-provider-engine": "14.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.5",
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/fill-scenarios": "^1.0.1-rc.3",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.4",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.3",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"@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",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "3.0.22",
|
||||
|
@ -1,7 +1,14 @@
|
||||
import { AbiDecoder, intervalUtils, logUtils } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
import { BlockParamLiteral, ContractAbi, FilterObject, LogEntry, LogWithDecodedArgs, RawLog } from 'ethereum-types';
|
||||
import {
|
||||
BlockParamLiteral,
|
||||
ContractAbi,
|
||||
ContractArtifact,
|
||||
FilterObject,
|
||||
LogEntry,
|
||||
LogWithDecodedArgs,
|
||||
RawLog,
|
||||
} from 'ethereum-types';
|
||||
import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// tslint:disable:no-unused-variable
|
||||
// tslint:disable:no-unbound-method
|
||||
import { BaseContract } from '@0xproject/base-contract';
|
||||
import { BlockParam, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types';
|
||||
import { BigNumber, classUtils, logUtils } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as ethers from 'ethers';
|
||||
|
@ -40,6 +40,7 @@
|
||||
"MultiSigWallet",
|
||||
"MultiSigWalletWithTimeLock",
|
||||
"OrderValidator",
|
||||
"ReentrantERC20Token",
|
||||
"TestAssetProxyOwner",
|
||||
"TestAssetProxyDispatcher",
|
||||
"TestConstants",
|
||||
@ -47,6 +48,7 @@
|
||||
"TestLibs",
|
||||
"TestExchangeInternals",
|
||||
"TestSignatureValidator",
|
||||
"TestStaticCallReceiver",
|
||||
"TokenRegistry",
|
||||
"Validator",
|
||||
"Wallet",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "contracts",
|
||||
"version": "2.1.40",
|
||||
"version": "2.1.42",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -20,14 +20,11 @@
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha":
|
||||
"mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler --contracts-dir src",
|
||||
"clean": "shx rm -rf lib generated_contract_wrappers",
|
||||
"generate_contract_wrappers":
|
||||
"abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers",
|
||||
"lint":
|
||||
"tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
@ -36,8 +33,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|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
"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"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -50,12 +46,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/sol-cov": "^2.0.0",
|
||||
"@0xproject/subproviders": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/sol-compiler": "^1.0.5",
|
||||
"@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",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/ethereumjs-abi": "^0.6.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
@ -77,15 +73,15 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.3",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"@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",
|
||||
"@types/js-combinatorics": "^0.5.29",
|
||||
"bn.js": "^4.11.8",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethereumjs-abi": "0.6.5",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "3.0.22",
|
||||
|
@ -37,7 +37,7 @@ contract Whitelist is
|
||||
bytes internal TX_ORIGIN_SIGNATURE;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x06";
|
||||
byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x05";
|
||||
|
||||
constructor (address _exchange)
|
||||
public
|
||||
|
@ -163,7 +163,7 @@ contract MixinExchangeWrapper is
|
||||
|
||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount,
|
||||
remainingMakerAssetFillAmount
|
||||
@ -231,7 +231,7 @@ contract MixinExchangeWrapper is
|
||||
|
||||
// Convert the remaining amount of ZRX to buy into remaining amount
|
||||
// of WETH to sell, assuming entire amount can be sold in the current order.
|
||||
uint256 remainingWethSellAmount = getPartialAmount(
|
||||
uint256 remainingWethSellAmount = getPartialAmountFloor(
|
||||
orders[i].takerAssetAmount,
|
||||
safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees
|
||||
remainingZrxBuyAmount
|
||||
|
@ -87,7 +87,7 @@ contract MixinForwarderCore is
|
||||
uint256 makerAssetAmountPurchased;
|
||||
if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
|
||||
// Calculate amount of WETH that won't be spent on ETH fees.
|
||||
wethSellAmount = getPartialAmount(
|
||||
wethSellAmount = getPartialAmountFloor(
|
||||
PERCENTAGE_DENOMINATOR,
|
||||
safeAdd(PERCENTAGE_DENOMINATOR, feePercentage),
|
||||
msg.value
|
||||
@ -103,7 +103,7 @@ contract MixinForwarderCore is
|
||||
makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid);
|
||||
} else {
|
||||
// 5% of WETH is reserved for filling feeOrders and paying feeRecipient.
|
||||
wethSellAmount = getPartialAmount(
|
||||
wethSellAmount = getPartialAmountFloor(
|
||||
MAX_WETH_FILL_PERCENTAGE,
|
||||
PERCENTAGE_DENOMINATOR,
|
||||
msg.value
|
||||
|
@ -82,7 +82,7 @@ contract MixinWeth is
|
||||
uint256 wethRemaining = safeSub(msg.value, wethSold);
|
||||
|
||||
// Calculate ETH fee to pay to feeRecipient.
|
||||
uint256 ethFee = getPartialAmount(
|
||||
uint256 ethFee = getPartialAmountFloor(
|
||||
feePercentage,
|
||||
PERCENTAGE_DENOMINATOR,
|
||||
wethSoldExcludingFeeOrders
|
||||
|
@ -118,6 +118,9 @@ contract ERC20Proxy is
|
||||
mstore(96, 0)
|
||||
revert(0, 100)
|
||||
}
|
||||
|
||||
// Revert if undefined function is called
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,9 @@ contract ERC721Proxy is
|
||||
mstore(96, 0)
|
||||
revert(0, 100)
|
||||
}
|
||||
|
||||
// Revert if undefined function is called
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ contract MixinAssetProxyDispatcher is
|
||||
internal
|
||||
{
|
||||
// Do nothing if no amount should be transferred.
|
||||
if (amount > 0) {
|
||||
if (amount > 0 && from != to) {
|
||||
// Ensure assetData length is valid
|
||||
require(
|
||||
assetData.length > 3,
|
||||
|
@ -19,6 +19,7 @@
|
||||
pragma solidity 0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
@ -30,6 +31,7 @@ import "./mixins/MAssetProxyDispatcher.sol";
|
||||
|
||||
|
||||
contract MixinExchangeCore is
|
||||
ReentrancyGuard,
|
||||
LibConstants,
|
||||
LibMath,
|
||||
LibOrder,
|
||||
@ -54,6 +56,7 @@ contract MixinExchangeCore is
|
||||
/// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
|
||||
function cancelOrdersUpTo(uint256 targetOrderEpoch)
|
||||
external
|
||||
nonReentrant
|
||||
{
|
||||
address makerAddress = getCurrentContextAddress();
|
||||
// If this function is called via `executeTransaction`, we only update the orderEpoch for the makerAddress/msg.sender combination.
|
||||
@ -86,43 +89,14 @@ contract MixinExchangeCore is
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
nonReentrant
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
// Fetch order info
|
||||
OrderInfo memory orderInfo = getOrderInfo(order);
|
||||
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Get amount of takerAsset to fill
|
||||
uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
|
||||
uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
|
||||
// Validate context
|
||||
assertValidFill(
|
||||
fillResults = fillOrderInternal(
|
||||
order,
|
||||
orderInfo,
|
||||
takerAddress,
|
||||
takerAssetFillAmount,
|
||||
takerAssetFilledAmount,
|
||||
signature
|
||||
);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
fillResults = calculateFillResults(order, takerAssetFilledAmount);
|
||||
|
||||
// Update exchange internal state
|
||||
updateFilledState(
|
||||
order,
|
||||
takerAddress,
|
||||
orderInfo.orderHash,
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
fillResults
|
||||
);
|
||||
|
||||
// Settle order
|
||||
settleOrder(order, takerAddress, fillResults);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
@ -131,6 +105,7 @@ contract MixinExchangeCore is
|
||||
/// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
|
||||
function cancelOrder(Order memory order)
|
||||
public
|
||||
nonReentrant
|
||||
{
|
||||
// Fetch current order status
|
||||
OrderInfo memory orderInfo = getOrderInfo(order);
|
||||
@ -203,6 +178,64 @@ contract MixinExchangeCore is
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrderInternal(
|
||||
Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
// Fetch order info
|
||||
OrderInfo memory orderInfo = getOrderInfo(order);
|
||||
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Assert that the order is fillable by taker
|
||||
assertFillableOrder(
|
||||
order,
|
||||
orderInfo,
|
||||
takerAddress,
|
||||
signature
|
||||
);
|
||||
|
||||
// Get amount of takerAsset to fill
|
||||
uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
|
||||
uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
|
||||
// Validate context
|
||||
assertValidFill(
|
||||
order,
|
||||
orderInfo,
|
||||
takerAssetFillAmount,
|
||||
takerAssetFilledAmount,
|
||||
fillResults.makerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
fillResults = calculateFillResults(order, takerAssetFilledAmount);
|
||||
|
||||
// Update exchange internal state
|
||||
updateFilledState(
|
||||
order,
|
||||
takerAddress,
|
||||
orderInfo.orderHash,
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
fillResults
|
||||
);
|
||||
|
||||
// Settle order
|
||||
settleOrder(order, takerAddress, fillResults);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
/// @param takerAddress Address of taker who filled the order.
|
||||
@ -264,15 +297,11 @@ contract MixinExchangeCore is
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
function assertFillableOrder(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo,
|
||||
address takerAddress,
|
||||
uint256 takerAssetFillAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
@ -284,12 +313,6 @@ contract MixinExchangeCore is
|
||||
"ORDER_UNFILLABLE"
|
||||
);
|
||||
|
||||
// Revert if fill amount is invalid
|
||||
require(
|
||||
takerAssetFillAmount != 0,
|
||||
"INVALID_TAKER_AMOUNT"
|
||||
);
|
||||
|
||||
// Validate sender is allowed to fill this order
|
||||
if (order.senderAddress != address(0)) {
|
||||
require(
|
||||
@ -317,10 +340,74 @@ contract MixinExchangeCore is
|
||||
"INVALID_ORDER_SIGNATURE"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
|
||||
function assertValidFill(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo,
|
||||
uint256 takerAssetFillAmount, // TODO: use FillResults
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 makerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
view
|
||||
{
|
||||
// Revert if fill amount is invalid
|
||||
// TODO: reconsider necessity for v2.1
|
||||
require(
|
||||
takerAssetFillAmount != 0,
|
||||
"INVALID_TAKER_AMOUNT"
|
||||
);
|
||||
|
||||
// Make sure taker does not pay more than desired amount
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
require(
|
||||
takerAssetFilledAmount <= takerAssetFillAmount,
|
||||
"TAKER_OVERPAY"
|
||||
);
|
||||
|
||||
// Make sure order is not overfilled
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
require(
|
||||
safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount) <= order.takerAssetAmount,
|
||||
"ORDER_OVERFILL"
|
||||
);
|
||||
|
||||
// Make sure order is filled at acceptable price.
|
||||
// The order has an implied price from the makers perspective:
|
||||
// order price = order.makerAssetAmount / order.takerAssetAmount
|
||||
// i.e. the number of makerAsset maker is paying per takerAsset. The
|
||||
// maker is guaranteed to get this price or a better (lower) one. The
|
||||
// actual price maker is getting in this fill is:
|
||||
// fill price = makerAssetFilledAmount / takerAssetFilledAmount
|
||||
// We need `fill price <= order price` for the fill to be fair to maker.
|
||||
// This amounts to:
|
||||
// makerAssetFilledAmount order.makerAssetAmount
|
||||
// ------------------------ <= -----------------------
|
||||
// takerAssetFilledAmount order.takerAssetAmount
|
||||
// or, equivalently:
|
||||
// makerAssetFilledAmount * order.takerAssetAmount <=
|
||||
// order.makerAssetAmount * takerAssetFilledAmount
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
require(
|
||||
safeMul(makerAssetFilledAmount, order.takerAssetAmount)
|
||||
<=
|
||||
safeMul(order.makerAssetAmount, takerAssetFilledAmount),
|
||||
"INVALID_FILL_PRICE"
|
||||
);
|
||||
|
||||
// Validate fill order rounding
|
||||
require(
|
||||
!isRoundingError(
|
||||
!isRoundingErrorFloor(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount
|
||||
@ -376,17 +463,17 @@ contract MixinExchangeCore is
|
||||
{
|
||||
// Compute proportional transfer amounts
|
||||
fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
|
||||
fillResults.makerAssetFilledAmount = getPartialAmount(
|
||||
fillResults.makerAssetFilledAmount = getPartialAmountFloor(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount
|
||||
);
|
||||
fillResults.makerFeePaid = getPartialAmount(
|
||||
fillResults.makerFeePaid = getPartialAmountFloor(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerFee
|
||||
);
|
||||
fillResults.takerFeePaid = getPartialAmount(
|
||||
fillResults.takerFeePaid = getPartialAmountFloor(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.takerFee
|
||||
|
@ -14,6 +14,7 @@
|
||||
pragma solidity 0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
@ -25,6 +26,7 @@ import "./mixins/MAssetProxyDispatcher.sol";
|
||||
|
||||
|
||||
contract MixinMatchOrders is
|
||||
ReentrancyGuard,
|
||||
LibConstants,
|
||||
LibMath,
|
||||
MAssetProxyDispatcher,
|
||||
@ -48,6 +50,7 @@ contract MixinMatchOrders is
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public
|
||||
nonReentrant
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData.
|
||||
@ -63,6 +66,18 @@ contract MixinMatchOrders is
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Either our context is valid or we revert
|
||||
assertFillableOrder(
|
||||
leftOrder,
|
||||
leftOrderInfo,
|
||||
takerAddress,
|
||||
leftSignature
|
||||
);
|
||||
assertFillableOrder(
|
||||
rightOrder,
|
||||
rightOrderInfo,
|
||||
takerAddress,
|
||||
rightSignature
|
||||
);
|
||||
assertValidMatch(leftOrder, rightOrder);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
@ -77,18 +92,16 @@ contract MixinMatchOrders is
|
||||
assertValidFill(
|
||||
leftOrder,
|
||||
leftOrderInfo,
|
||||
takerAddress,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
leftSignature
|
||||
matchedFillResults.left.makerAssetFilledAmount
|
||||
);
|
||||
assertValidFill(
|
||||
rightOrder,
|
||||
rightOrderInfo,
|
||||
takerAddress,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
rightSignature
|
||||
matchedFillResults.right.makerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Update exchange state
|
||||
@ -162,62 +175,85 @@ contract MixinMatchOrders is
|
||||
pure
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// We settle orders at the exchange rate of the right order.
|
||||
// The amount saved by the left maker goes to the taker.
|
||||
// Either the left or right order will be fully filled; possibly both.
|
||||
// The left order is fully filled iff the right order can sell more than left can buy.
|
||||
// That is: the amount required to fill the left order is less than or equal to
|
||||
// the amount we can spend from the right order:
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightMakerToTakerRatio>
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount>
|
||||
// <leftTakerAssetAmountRemaining> * <rightOrder.takerAssetAmount> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount>
|
||||
// Derive maker asset amounts for left & right orders, given store taker assert amounts
|
||||
uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount);
|
||||
uint256 leftMakerAssetAmountRemaining = getPartialAmountFloor(
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
leftTakerAssetAmountRemaining
|
||||
);
|
||||
uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount);
|
||||
uint256 leftTakerAssetFilledAmount;
|
||||
uint256 rightTakerAssetFilledAmount;
|
||||
if (
|
||||
safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <=
|
||||
safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount)
|
||||
) {
|
||||
// Left order will be fully filled: maximally fill left
|
||||
leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining;
|
||||
|
||||
// The right order receives an amount proportional to how much was spent.
|
||||
rightTakerAssetFilledAmount = getPartialAmount(
|
||||
rightOrder.takerAssetAmount,
|
||||
uint256 rightMakerAssetAmountRemaining = getPartialAmountFloor(
|
||||
rightOrder.makerAssetAmount,
|
||||
leftTakerAssetFilledAmount
|
||||
rightOrder.takerAssetAmount,
|
||||
rightTakerAssetAmountRemaining
|
||||
);
|
||||
|
||||
// Calculate fill results for maker and taker assets: at least one order will be fully filled.
|
||||
// The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining`
|
||||
// The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining`
|
||||
// We have two distinct cases for calculating the fill results:
|
||||
// Case 1.
|
||||
// If the left maker can buy more than the right maker can sell, then only the right order is fully filled.
|
||||
// If the left maker can buy exactly what the right maker can sell, then both orders are fully filled.
|
||||
// Case 2.
|
||||
// If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled.
|
||||
if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) {
|
||||
// Case 1: Right order is fully filled
|
||||
matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining;
|
||||
matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining;
|
||||
matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount;
|
||||
// Round down to ensure the maker's exchange rate does not exceed the price specified by the order.
|
||||
// We favor the maker when the exchange rate must be rounded.
|
||||
matchedFillResults.left.makerAssetFilledAmount = getPartialAmountFloor(
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount
|
||||
);
|
||||
} else {
|
||||
// Right order will be fully filled: maximally fill right
|
||||
rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining;
|
||||
|
||||
// The left order receives an amount proportional to how much was spent.
|
||||
leftTakerAssetFilledAmount = getPartialAmount(
|
||||
rightOrder.makerAssetAmount,
|
||||
// Case 2: Left order is fully filled
|
||||
matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining;
|
||||
matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining;
|
||||
matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount;
|
||||
// Round up to ensure the maker's exchange rate does not exceed the price specified by the order.
|
||||
// We favor the maker when the exchange rate must be rounded.
|
||||
matchedFillResults.right.takerAssetFilledAmount = getPartialAmountCeil(
|
||||
rightOrder.takerAssetAmount,
|
||||
rightTakerAssetFilledAmount
|
||||
rightOrder.makerAssetAmount,
|
||||
matchedFillResults.right.makerAssetFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate fill results for left order
|
||||
matchedFillResults.left = calculateFillResults(
|
||||
leftOrder,
|
||||
leftTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate fill results for right order
|
||||
matchedFillResults.right = calculateFillResults(
|
||||
rightOrder,
|
||||
rightTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate amount given to taker
|
||||
matchedFillResults.leftMakerAssetSpreadAmount = safeSub(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Compute fees for left order
|
||||
matchedFillResults.left.makerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.makerFee
|
||||
);
|
||||
matchedFillResults.left.takerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
leftOrder.takerFee
|
||||
);
|
||||
|
||||
// Compute fees for right order
|
||||
matchedFillResults.right.makerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.right.makerAssetFilledAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.makerFee
|
||||
);
|
||||
matchedFillResults.right.takerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.takerFee
|
||||
);
|
||||
|
||||
// Return fill results
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
pragma solidity 0.4.24;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
import "./interfaces/IWallet.sol";
|
||||
@ -26,6 +27,7 @@ import "./interfaces/IValidator.sol";
|
||||
|
||||
|
||||
contract MixinSignatureValidator is
|
||||
ReentrancyGuard,
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
@ -48,6 +50,7 @@ contract MixinSignatureValidator is
|
||||
)
|
||||
external
|
||||
{
|
||||
if (signerAddress != msg.sender) {
|
||||
require(
|
||||
isValidSignature(
|
||||
hash,
|
||||
@ -56,6 +59,7 @@ contract MixinSignatureValidator is
|
||||
),
|
||||
"INVALID_SIGNATURE"
|
||||
);
|
||||
}
|
||||
preSigned[hash][signerAddress] = true;
|
||||
}
|
||||
|
||||
@ -67,6 +71,7 @@ contract MixinSignatureValidator is
|
||||
bool approval
|
||||
)
|
||||
external
|
||||
nonReentrant
|
||||
{
|
||||
address signerAddress = getCurrentContextAddress();
|
||||
allowedValidators[signerAddress][validatorAddress] = approval;
|
||||
@ -172,26 +177,14 @@ contract MixinSignatureValidator is
|
||||
isValid = signerAddress == recovered;
|
||||
return isValid;
|
||||
|
||||
// Implicitly signed by caller.
|
||||
// The signer has initiated the call. In the case of non-contract
|
||||
// accounts it means the transaction itself was signed.
|
||||
// Example: let's say for a particular operation three signatures
|
||||
// A, B and C are required. To submit the transaction, A and B can
|
||||
// give a signature to C, who can then submit the transaction using
|
||||
// `Caller` for his own signature. Or A and C can sign and B can
|
||||
// submit using `Caller`. Having `Caller` allows this flexibility.
|
||||
} else if (signatureType == SignatureType.Caller) {
|
||||
require(
|
||||
signature.length == 0,
|
||||
"LENGTH_0_REQUIRED"
|
||||
);
|
||||
isValid = signerAddress == msg.sender;
|
||||
return isValid;
|
||||
|
||||
// Signature verified by wallet contract.
|
||||
// If used with an order, the maker of the order is the wallet contract.
|
||||
} else if (signatureType == SignatureType.Wallet) {
|
||||
isValid = IWallet(signerAddress).isValidSignature(hash, signature);
|
||||
isValid = isValidWalletSignature(
|
||||
hash,
|
||||
signerAddress,
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
|
||||
// Signature verified by validator contract.
|
||||
@ -209,7 +202,8 @@ contract MixinSignatureValidator is
|
||||
if (!allowedValidators[signerAddress][validatorAddress]) {
|
||||
return false;
|
||||
}
|
||||
isValid = IValidator(validatorAddress).isValidSignature(
|
||||
isValid = isValidValidatorSignature(
|
||||
validatorAddress,
|
||||
hash,
|
||||
signerAddress,
|
||||
signature
|
||||
@ -220,34 +214,6 @@ contract MixinSignatureValidator is
|
||||
} else if (signatureType == SignatureType.PreSigned) {
|
||||
isValid = preSigned[hash][signerAddress];
|
||||
return isValid;
|
||||
|
||||
// Signature from Trezor hardware wallet.
|
||||
// It differs from web3.eth_sign in the encoding of message length
|
||||
// (Bitcoin varint encoding vs ascii-decimal, the latter is not
|
||||
// self-terminating which leads to ambiguities).
|
||||
// See also:
|
||||
// https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||
// https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c#L602
|
||||
// https://github.com/trezor/trezor-mcu/blob/master/firmware/crypto.c#L36
|
||||
} else if (signatureType == SignatureType.Trezor) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
"LENGTH_65_REQUIRED"
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = signature.readBytes32(1);
|
||||
s = signature.readBytes32(33);
|
||||
recovered = ecrecover(
|
||||
keccak256(abi.encodePacked(
|
||||
"\x19Ethereum Signed Message:\n\x20",
|
||||
hash
|
||||
)),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
isValid = signerAddress == recovered;
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// Anything else is illegal (We do not return false because
|
||||
@ -257,4 +223,102 @@ contract MixinSignatureValidator is
|
||||
// signature was invalid.)
|
||||
revert("SIGNATURE_UNSUPPORTED");
|
||||
}
|
||||
|
||||
/// @dev Verifies signature using logic defined by Wallet contract.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param walletAddress Address that should have signed the given hash
|
||||
/// and defines its own signature verification method.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
/// @return True if signature is valid for given wallet..
|
||||
function isValidWalletSignature(
|
||||
bytes32 hash,
|
||||
address walletAddress,
|
||||
bytes signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
bytes memory calldata = abi.encodeWithSelector(
|
||||
IWallet(walletAddress).isValidSignature.selector,
|
||||
hash,
|
||||
signature
|
||||
);
|
||||
assembly {
|
||||
let cdStart := add(calldata, 32)
|
||||
let success := staticcall(
|
||||
gas, // forward all gas
|
||||
walletAddress, // address of Wallet contract
|
||||
cdStart, // pointer to start of input
|
||||
mload(calldata), // length of input
|
||||
cdStart, // write input over output
|
||||
32 // output size is 32 bytes
|
||||
)
|
||||
|
||||
switch success
|
||||
case 0 {
|
||||
// Revert with `Error("WALLET_ERROR")`
|
||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||
mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
|
||||
mstore(96, 0)
|
||||
revert(0, 100)
|
||||
}
|
||||
case 1 {
|
||||
// Signature is valid if call did not revert and returned true
|
||||
isValid := mload(cdStart)
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/// @dev Verifies signature using logic defined by Validator contract.
|
||||
/// @param validatorAddress Address of validator contract.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param signerAddress Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
/// @return True if the address recovered from the provided signature matches the input signer address.
|
||||
function isValidValidatorSignature(
|
||||
address validatorAddress,
|
||||
bytes32 hash,
|
||||
address signerAddress,
|
||||
bytes signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
bytes memory calldata = abi.encodeWithSelector(
|
||||
IValidator(signerAddress).isValidSignature.selector,
|
||||
hash,
|
||||
signerAddress,
|
||||
signature
|
||||
);
|
||||
assembly {
|
||||
let cdStart := add(calldata, 32)
|
||||
let success := staticcall(
|
||||
gas, // forward all gas
|
||||
validatorAddress, // address of Validator contract
|
||||
cdStart, // pointer to start of input
|
||||
mload(calldata), // length of input
|
||||
cdStart, // write input over output
|
||||
32 // output size is 32 bytes
|
||||
)
|
||||
|
||||
switch success
|
||||
case 0 {
|
||||
// Revert with `Error("VALIDATOR_ERROR")`
|
||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||
mstore(64, 0x0000000f56414c494441544f525f4552524f5200000000000000000000000000)
|
||||
mstore(96, 0)
|
||||
revert(0, 100)
|
||||
}
|
||||
case 1 {
|
||||
// Signature is valid if call did not revert and returned true
|
||||
isValid := mload(cdStart)
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,8 @@ contract MixinTransactions is
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
address contextAddress = currentContextAddress == address(0) ? msg.sender : currentContextAddress;
|
||||
address currentContextAddress_ = currentContextAddress;
|
||||
address contextAddress = currentContextAddress_ == address(0) ? msg.sender : currentContextAddress_;
|
||||
return contextAddress;
|
||||
}
|
||||
}
|
||||
|
@ -19,18 +19,22 @@
|
||||
pragma solidity 0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibAbiEncoder.sol";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
import "./mixins/MWrapperFunctions.sol";
|
||||
|
||||
|
||||
contract MixinWrapperFunctions is
|
||||
ReentrancyGuard,
|
||||
LibMath,
|
||||
LibFillResults,
|
||||
LibAbiEncoder,
|
||||
MExchangeCore
|
||||
MExchangeCore,
|
||||
MWrapperFunctions
|
||||
{
|
||||
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
@ -43,17 +47,14 @@ contract MixinWrapperFunctions is
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
nonReentrant
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
fillResults = fillOrder(
|
||||
fillResults = fillOrKillOrderInternal(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
require(
|
||||
fillResults.takerAssetFilledAmount == takerAssetFillAmount,
|
||||
"COMPLETE_FILL_FAILED"
|
||||
);
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
@ -88,14 +89,7 @@ contract MixinWrapperFunctions 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)))
|
||||
@ -117,11 +111,12 @@ contract MixinWrapperFunctions is
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
nonReentrant
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
for (uint256 i = 0; i != ordersLength; i++) {
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
FillResults memory singleFillResults = fillOrderInternal(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
@ -143,11 +138,12 @@ contract MixinWrapperFunctions is
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
nonReentrant
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
for (uint256 i = 0; i != ordersLength; i++) {
|
||||
FillResults memory singleFillResults = fillOrKillOrder(
|
||||
FillResults memory singleFillResults = fillOrKillOrderInternal(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
@ -195,6 +191,7 @@ contract MixinWrapperFunctions is
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
nonReentrant
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
@ -210,7 +207,7 @@ contract MixinWrapperFunctions is
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
FillResults memory singleFillResults = fillOrderInternal(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
@ -282,6 +279,7 @@ contract MixinWrapperFunctions is
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
nonReentrant
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
@ -298,14 +296,14 @@ contract MixinWrapperFunctions is
|
||||
|
||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount,
|
||||
remainingMakerAssetFillAmount
|
||||
);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
FillResults memory singleFillResults = fillOrderInternal(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
@ -350,7 +348,7 @@ contract MixinWrapperFunctions is
|
||||
|
||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount,
|
||||
remainingMakerAssetFillAmount
|
||||
@ -400,4 +398,28 @@ contract MixinWrapperFunctions is
|
||||
}
|
||||
return ordersInfo;
|
||||
}
|
||||
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
function fillOrKillOrderInternal(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
fillResults = fillOrderInternal(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
require(
|
||||
fillResults.takerAssetFilledAmount == takerAssetFillAmount,
|
||||
"COMPLETE_FILL_FAILED"
|
||||
);
|
||||
return fillResults;
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,12 @@ contract LibMath is
|
||||
SafeMath
|
||||
{
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @dev Calculates partial value given a numerator and denominator rounded down.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmount(
|
||||
/// @return Partial value of target rounded down.
|
||||
function getPartialAmountFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
@ -39,6 +39,11 @@ contract LibMath is
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
require(
|
||||
denominator > 0,
|
||||
"DIVISION_BY_ZERO"
|
||||
);
|
||||
|
||||
partialAmount = safeDiv(
|
||||
safeMul(numerator, target),
|
||||
denominator
|
||||
@ -46,12 +51,44 @@ contract LibMath is
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @dev Calculates partial value given a numerator and denominator rounded down.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target rounded up.
|
||||
function getPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
require(
|
||||
denominator > 0,
|
||||
"DIVISION_BY_ZERO"
|
||||
);
|
||||
|
||||
// safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
|
||||
// ceil(a / b) = floor((a + b - 1) / b)
|
||||
// To implement `ceil(a / b)` using safeDiv.
|
||||
partialAmount = safeDiv(
|
||||
safeAdd(
|
||||
safeMul(numerator, target),
|
||||
safeSub(denominator, 1)
|
||||
),
|
||||
denominator
|
||||
);
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error >= 0.1% when rounding down.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingError(
|
||||
function isRoundingErrorFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
@ -60,16 +97,73 @@ contract LibMath is
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
uint256 remainder = mulmod(target, numerator, denominator);
|
||||
if (remainder == 0) {
|
||||
return false; // No rounding error.
|
||||
require(
|
||||
denominator > 0,
|
||||
"DIVISION_BY_ZERO"
|
||||
);
|
||||
|
||||
// The absolute rounding error is the difference between the rounded
|
||||
// value and the ideal value. The relative rounding error is the
|
||||
// absolute rounding error divided by the absolute value of the
|
||||
// ideal value. This is undefined when the ideal value is zero.
|
||||
//
|
||||
// The ideal value is `numerator * target / denominator`.
|
||||
// Let's call `numerator * target % denominator` the remainder.
|
||||
// The absolute error is `remainder / denominator`.
|
||||
//
|
||||
// When the ideal value is zero, we require the absolute error to
|
||||
// be zero. Fortunately, this is always the case. The ideal value is
|
||||
// zero iff `numerator == 0` and/or `target == 0`. In this case the
|
||||
// remainder and absolute error are also zero.
|
||||
if (target == 0 || numerator == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 errPercentageTimes1000000 = safeDiv(
|
||||
safeMul(remainder, 1000000),
|
||||
safeMul(numerator, target)
|
||||
// Otherwise, we want the relative rounding error to be strictly
|
||||
// less than 0.1%.
|
||||
// The relative error is `remainder / (numerator * target)`.
|
||||
// We want the relative error less than 1 / 1000:
|
||||
// remainder / (numerator * denominator) < 1 / 1000
|
||||
// or equivalently:
|
||||
// 1000 * remainder < numerator * target
|
||||
// so we have a rounding error iff:
|
||||
// 1000 * remainder >= numerator * target
|
||||
uint256 remainder = mulmod(target, numerator, denominator);
|
||||
isError = safeMul(1000, remainder) >= safeMul(numerator, target);
|
||||
return isError;
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error >= 0.1% when rounding up.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingErrorCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
require(
|
||||
denominator > 0,
|
||||
"DIVISION_BY_ZERO"
|
||||
);
|
||||
isError = errPercentageTimes1000000 > 1000;
|
||||
|
||||
// See the comments in `isRoundingError`.
|
||||
if (target == 0 || numerator == 0) {
|
||||
// When either is zero, the ideal value and rounded value are zero
|
||||
// and there is no rounding error. (Although the relative error
|
||||
// is undefined.)
|
||||
return false;
|
||||
}
|
||||
// Compute remainder as before
|
||||
uint256 remainder = mulmod(target, numerator, denominator);
|
||||
// TODO: safeMod
|
||||
remainder = safeSub(denominator, remainder) % denominator;
|
||||
isError = safeMul(1000, remainder) >= safeMul(numerator, target);
|
||||
return isError;
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,19 @@ contract MExchangeCore is
|
||||
uint256 orderEpoch // Orders with specified makerAddress and senderAddress with a salt less than this value are considered cancelled.
|
||||
);
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrderInternal(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
/// @param takerAddress Address of taker who filled the order.
|
||||
@ -86,18 +99,30 @@ contract MExchangeCore is
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo Status, orderHash, and amount already filled of order.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
function assertFillableOrder(
|
||||
LibOrder.Order memory order,
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
address takerAddress,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
view;
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo Status, orderHash, and amount already filled of order.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
|
||||
function assertValidFill(
|
||||
LibOrder.Order memory order,
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 takerAssetFillAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
bytes memory signature
|
||||
uint256 makerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
view;
|
||||
|
@ -36,11 +36,40 @@ contract MSignatureValidator is
|
||||
Invalid, // 0x01
|
||||
EIP712, // 0x02
|
||||
EthSign, // 0x03
|
||||
Caller, // 0x04
|
||||
Wallet, // 0x05
|
||||
Validator, // 0x06
|
||||
PreSigned, // 0x07
|
||||
Trezor, // 0x08
|
||||
NSignatureTypes // 0x09, number of signature types. Always leave at end.
|
||||
Wallet, // 0x04
|
||||
Validator, // 0x05
|
||||
PreSigned, // 0x06
|
||||
NSignatureTypes // 0x07, number of signature types. Always leave at end.
|
||||
}
|
||||
|
||||
/// @dev Verifies signature using logic defined by Wallet contract.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param walletAddress Address that should have signed the given hash
|
||||
/// and defines its own signature verification method.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
/// @return True if the address recovered from the provided signature matches the input signer address.
|
||||
function isValidWalletSignature(
|
||||
bytes32 hash,
|
||||
address walletAddress,
|
||||
bytes signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool isValid);
|
||||
|
||||
/// @dev Verifies signature using logic defined by Validator contract.
|
||||
/// @param validatorAddress Address of validator contract.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param signerAddress Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
/// @return True if the address recovered from the provided signature matches the input signer address.
|
||||
function isValidValidatorSignature(
|
||||
address validatorAddress,
|
||||
bytes32 hash,
|
||||
address signerAddress,
|
||||
bytes signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
||||
|
40
packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol
vendored
Normal file
40
packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity 0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
import "../interfaces/IWrapperFunctions.sol";
|
||||
|
||||
|
||||
contract MWrapperFunctions {
|
||||
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
/// @param order LibOrder.Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
function fillOrKillOrderInternal(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
}
|
182
packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol
vendored
Normal file
182
packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity 0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../tokens/ERC20Token/ERC20Token.sol";
|
||||
import "../../protocol/Exchange/interfaces/IExchange.sol";
|
||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
||||
|
||||
|
||||
contract ReentrantERC20Token is
|
||||
ERC20Token
|
||||
{
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
|
||||
bytes internal constant REENTRANCY_ILLEGAL_REVERT_REASON = abi.encodeWithSelector(
|
||||
bytes4(keccak256("Error(string)")),
|
||||
"REENTRANCY_ILLEGAL"
|
||||
);
|
||||
|
||||
// All of these functions are potentially vulnerable to reentrancy
|
||||
// We do not test any "noThrow" functions because `fillOrderNoThrow` makes a delegatecall to `fillOrder`
|
||||
enum ExchangeFunction {
|
||||
FILL_ORDER,
|
||||
FILL_OR_KILL_ORDER,
|
||||
BATCH_FILL_ORDERS,
|
||||
BATCH_FILL_OR_KILL_ORDERS,
|
||||
MARKET_BUY_ORDERS,
|
||||
MARKET_SELL_ORDERS,
|
||||
MATCH_ORDERS,
|
||||
CANCEL_ORDER,
|
||||
CANCEL_ORDERS_UP_TO,
|
||||
SET_SIGNATURE_VALIDATOR_APPROVAL
|
||||
}
|
||||
|
||||
uint8 internal currentFunctionId = 0;
|
||||
|
||||
constructor (address _exchange)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
}
|
||||
|
||||
/// @dev Set the current function that will be called when `transferFrom` is called.
|
||||
/// @param _currentFunctionId Id that corresponds to function name.
|
||||
function setCurrentFunction(uint8 _currentFunctionId)
|
||||
external
|
||||
{
|
||||
currentFunctionId = _currentFunctionId;
|
||||
}
|
||||
|
||||
/// @dev A version of `transferFrom` that attempts to reenter the Exchange contract.
|
||||
/// @param _from The address of the sender
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
function transferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
// This order would normally be invalid, but it will be used strictly for testing reentrnacy.
|
||||
// Any reentrancy checks will happen before any other checks that invalidate the order.
|
||||
LibOrder.Order memory order;
|
||||
|
||||
// Initialize remaining null parameters
|
||||
bytes memory signature;
|
||||
LibOrder.Order[] memory orders;
|
||||
uint256[] memory takerAssetFillAmounts;
|
||||
bytes[] memory signatures;
|
||||
bytes memory calldata;
|
||||
|
||||
// Create calldata for function that corresponds to currentFunctionId
|
||||
if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.fillOrder.selector,
|
||||
order,
|
||||
0,
|
||||
signature
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.FILL_OR_KILL_ORDER)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.fillOrKillOrder.selector,
|
||||
order,
|
||||
0,
|
||||
signature
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.batchFillOrders.selector,
|
||||
orders,
|
||||
takerAssetFillAmounts,
|
||||
signatures
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_OR_KILL_ORDERS)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.batchFillOrKillOrders.selector,
|
||||
orders,
|
||||
takerAssetFillAmounts,
|
||||
signatures
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.marketBuyOrders.selector,
|
||||
orders,
|
||||
0,
|
||||
signatures
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.marketSellOrders.selector,
|
||||
orders,
|
||||
0,
|
||||
signatures
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.MATCH_ORDERS)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.matchOrders.selector,
|
||||
order,
|
||||
order,
|
||||
signature,
|
||||
signature
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDER)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.cancelOrder.selector,
|
||||
order
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDERS_UP_TO)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.cancelOrdersUpTo.selector,
|
||||
0
|
||||
);
|
||||
} else if (currentFunctionId == uint8(ExchangeFunction.SET_SIGNATURE_VALIDATOR_APPROVAL)) {
|
||||
calldata = abi.encodeWithSelector(
|
||||
EXCHANGE.setSignatureValidatorApproval.selector,
|
||||
address(0),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// Call Exchange function, swallow error
|
||||
address(EXCHANGE).call(calldata);
|
||||
|
||||
// Revert reason is 100 bytes
|
||||
bytes memory returnData = new bytes(100);
|
||||
|
||||
// Copy return data
|
||||
assembly {
|
||||
returndatacopy(add(returnData, 32), 0, 100)
|
||||
}
|
||||
|
||||
// Revert if function reverted with REENTRANCY_ILLEGAL error
|
||||
require(!REENTRANCY_ILLEGAL_REVERT_REASON.equals(returnData));
|
||||
|
||||
// Transfer will return true if function failed for any other reason
|
||||
return true;
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ contract TestExchangeInternals is
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function publicGetPartialAmount(
|
||||
function publicGetPartialAmountFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
@ -76,15 +76,32 @@ contract TestExchangeInternals is
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
return getPartialAmount(numerator, denominator, target);
|
||||
return getPartialAmountFloor(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function publicGetPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
return getPartialAmountCeil(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error >= 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function publicIsRoundingError(
|
||||
function publicIsRoundingErrorFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
@ -93,7 +110,24 @@ contract TestExchangeInternals is
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
return isRoundingError(numerator, denominator, target);
|
||||
return isRoundingErrorFloor(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error >= 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function publicIsRoundingErrorCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
return isRoundingErrorCeil(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
|
@ -49,7 +49,7 @@ contract TestLibs is
|
||||
return fillOrderCalldata;
|
||||
}
|
||||
|
||||
function publicGetPartialAmount(
|
||||
function publicGetPartialAmountFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
@ -58,7 +58,7 @@ contract TestLibs is
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
partialAmount = getPartialAmount(
|
||||
partialAmount = getPartialAmountFloor(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
@ -66,7 +66,24 @@ contract TestLibs is
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
function publicIsRoundingError(
|
||||
function publicGetPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
partialAmount = getPartialAmountCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
);
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
function publicIsRoundingErrorFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
@ -75,7 +92,24 @@ contract TestLibs is
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
isError = isRoundingError(
|
||||
isError = isRoundingErrorFloor(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
);
|
||||
return isError;
|
||||
}
|
||||
|
||||
function publicIsRoundingErrorCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
isError = isRoundingErrorCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
|
81
packages/contracts/src/2.0.0/test/TestStaticCallReceiver/TestStaticCallReceiver.sol
vendored
Normal file
81
packages/contracts/src/2.0.0/test/TestStaticCallReceiver/TestStaticCallReceiver.sol
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity 0.4.24;
|
||||
|
||||
import "../../tokens/ERC20Token/IERC20Token.sol";
|
||||
|
||||
|
||||
// solhint-disable no-unused-vars
|
||||
contract TestStaticCallReceiver {
|
||||
|
||||
uint256 internal state = 1;
|
||||
|
||||
/// @dev Updates state and returns true. Intended to be used with `Validator` signature type.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signerAddress Address that should have signed the given hash.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signerAddress,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
returns (bool isValid)
|
||||
{
|
||||
updateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Updates state and returns true. Intended to be used with `Wallet` signature type.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
returns (bool isValid)
|
||||
{
|
||||
updateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Approves an ERC20 token to spend tokens from this address.
|
||||
/// @param token Address of ERC20 token.
|
||||
/// @param spender Address that will spend tokens.
|
||||
/// @param value Amount of tokens spender is approved to spend.
|
||||
function approveERC20(
|
||||
address token,
|
||||
address spender,
|
||||
uint256 value
|
||||
)
|
||||
external
|
||||
{
|
||||
IERC20Token(token).approve(spender, value);
|
||||
}
|
||||
|
||||
/// @dev Increments state variable.
|
||||
function updateState()
|
||||
internal
|
||||
{
|
||||
state++;
|
||||
}
|
||||
}
|
44
packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol
vendored
Normal file
44
packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
pragma solidity 0.4.24;
|
||||
|
||||
|
||||
contract ReentrancyGuard {
|
||||
|
||||
// Locked state of mutex
|
||||
bool private locked = false;
|
||||
|
||||
/// @dev Functions with this modifer cannot be reentered. The mutex will be locked
|
||||
/// before function execution and unlocked after.
|
||||
modifier nonReentrant() {
|
||||
// Ensure mutex is unlocked
|
||||
require(
|
||||
!locked,
|
||||
"REENTRANCY_ILLEGAL"
|
||||
);
|
||||
|
||||
// Lock mutex before function call
|
||||
locked = true;
|
||||
|
||||
// Perform function call
|
||||
_;
|
||||
|
||||
// Unlock mutex after function call
|
||||
locked = false;
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_prox
|
||||
import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy';
|
||||
import { IAssetProxyContract } from '../../generated_contract_wrappers/i_asset_proxy';
|
||||
import { artifacts } from '../utils/artifacts';
|
||||
import { expectTransactionFailedAsync } from '../utils/assertions';
|
||||
import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
|
||||
import { chaiSetup } from '../utils/chai_setup';
|
||||
import { constants } from '../utils/constants';
|
||||
import { ERC20Wrapper } from '../utils/erc20_wrapper';
|
||||
@ -99,6 +99,17 @@ describe('Asset Transfer Proxies', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('Transfer Proxy - ERC20', () => {
|
||||
it('should revert if undefined function is called', async () => {
|
||||
const undefinedSelector = '0x01020304';
|
||||
await expectTransactionFailedWithoutReasonAsync(
|
||||
web3Wrapper.sendTransactionAsync({
|
||||
from: owner,
|
||||
to: erc20Proxy.address,
|
||||
value: constants.ZERO_AMOUNT,
|
||||
data: undefinedSelector,
|
||||
}),
|
||||
);
|
||||
});
|
||||
describe('transferFrom', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct ERC20 asset data
|
||||
@ -219,6 +230,17 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
describe('Transfer Proxy - ERC721', () => {
|
||||
it('should revert if undefined function is called', async () => {
|
||||
const undefinedSelector = '0x01020304';
|
||||
await expectTransactionFailedWithoutReasonAsync(
|
||||
web3Wrapper.sendTransactionAsync({
|
||||
from: owner,
|
||||
to: erc721Proxy.address,
|
||||
value: constants.ZERO_AMOUNT,
|
||||
data: undefinedSelector,
|
||||
}),
|
||||
);
|
||||
});
|
||||
describe('transferFrom', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct ERC721 asset data
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
|
||||
import { RevertReason, SignedOrder } from '@0xproject/types';
|
||||
import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
@ -14,6 +14,8 @@ import { DummyNoReturnERC20TokenContract } from '../../generated_contract_wrappe
|
||||
import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy';
|
||||
import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy';
|
||||
import { ExchangeCancelEventArgs, ExchangeContract } from '../../generated_contract_wrappers/exchange';
|
||||
import { ReentrantERC20TokenContract } from '../../generated_contract_wrappers/reentrant_erc20_token';
|
||||
import { TestStaticCallReceiverContract } from '../../generated_contract_wrappers/test_static_call_receiver';
|
||||
import { artifacts } from '../utils/artifacts';
|
||||
import { expectTransactionFailedAsync } from '../utils/assertions';
|
||||
import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
|
||||
@ -41,9 +43,12 @@ describe('Exchange core', () => {
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let noReturnErc20Token: DummyNoReturnERC20TokenContract;
|
||||
let reentrantErc20Token: ReentrantERC20TokenContract;
|
||||
let exchange: ExchangeContract;
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
let erc721Proxy: ERC721ProxyContract;
|
||||
let maliciousWallet: TestStaticCallReceiverContract;
|
||||
let maliciousValidator: TestStaticCallReceiverContract;
|
||||
|
||||
let signedOrder: SignedOrder;
|
||||
let erc20Balances: ERC20BalancesByOwner;
|
||||
@ -109,6 +114,18 @@ describe('Exchange core', () => {
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestStaticCallReceiver,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ReentrantERC20Token,
|
||||
provider,
|
||||
txDefaults,
|
||||
exchange.address,
|
||||
);
|
||||
|
||||
defaultMakerAssetAddress = erc20TokenA.address;
|
||||
defaultTakerAssetAddress = erc20TokenB.address;
|
||||
|
||||
@ -135,6 +152,26 @@ describe('Exchange core', () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync();
|
||||
});
|
||||
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow fillOrder to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
RevertReason.TransferFailed,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('fillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should throw if signature is invalid', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
@ -161,6 +198,51 @@ describe('Exchange core', () => {
|
||||
RevertReason.OrderUnfillable,
|
||||
);
|
||||
});
|
||||
|
||||
it('should revert if `isValidSignature` tries to update state when SignatureType=Wallet', async () => {
|
||||
const maliciousMakerAddress = maliciousWallet.address;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20TokenA.setBalance.sendTransactionAsync(
|
||||
maliciousMakerAddress,
|
||||
constants.INITIAL_ERC20_BALANCE,
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await maliciousWallet.approveERC20.sendTransactionAsync(
|
||||
erc20TokenA.address,
|
||||
erc20Proxy.address,
|
||||
constants.INITIAL_ERC20_ALLOWANCE,
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAddress: maliciousMakerAddress,
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
});
|
||||
signedOrder.signature = `0x0${SignatureType.Wallet}`;
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
RevertReason.WalletError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should revert if `isValidSignature` tries to update state when SignatureType=Validator', async () => {
|
||||
const isApproved = true;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await exchange.setSignatureValidatorApproval.sendTransactionAsync(
|
||||
maliciousValidator.address,
|
||||
isApproved,
|
||||
{ from: makerAddress },
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
signedOrder.signature = `${maliciousValidator.address}0${SignatureType.Validator}`;
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
RevertReason.ValidatorError,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Testing exchange of ERC20 tokens with no return values', () => {
|
||||
@ -448,7 +530,7 @@ describe('Exchange core', () => {
|
||||
// HACK(albrow): We need to hardcode the gas estimate here because
|
||||
// the Geth gas estimator doesn't work with the way we use
|
||||
// delegatecall and swallow errors.
|
||||
gas: 490000,
|
||||
gas: 600000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { Order, RevertReason, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { TestExchangeInternalsContract } from '../../generated_contract_wrappers/test_exchange_internals';
|
||||
@ -16,6 +17,8 @@ import { FillResults } from '../utils/types';
|
||||
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
||||
@ -43,26 +46,11 @@ const emptySignedOrder: SignedOrder = {
|
||||
|
||||
const overflowErrorForCall = new Error(RevertReason.Uint256Overflow);
|
||||
|
||||
async function referenceGetPartialAmountAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
const invalidOpcodeErrorForCall = new Error(await getInvalidOpcodeErrorMessageForCallAsync());
|
||||
const product = numerator.mul(target);
|
||||
if (product.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
if (denominator.eq(0)) {
|
||||
throw invalidOpcodeErrorForCall;
|
||||
}
|
||||
return product.dividedToIntegerBy(denominator);
|
||||
}
|
||||
|
||||
describe('Exchange core internal functions', () => {
|
||||
let testExchange: TestExchangeInternalsContract;
|
||||
let invalidOpcodeErrorForCall: Error | undefined;
|
||||
let overflowErrorForSendTransaction: Error | undefined;
|
||||
let divisionByZeroErrorForCall: Error | undefined;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@ -79,11 +67,29 @@ describe('Exchange core internal functions', () => {
|
||||
overflowErrorForSendTransaction = new Error(
|
||||
await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow),
|
||||
);
|
||||
divisionByZeroErrorForCall = new Error(
|
||||
await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.DivisionByZero),
|
||||
);
|
||||
invalidOpcodeErrorForCall = new Error(await getInvalidOpcodeErrorMessageForCallAsync());
|
||||
});
|
||||
// Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
|
||||
// the blockchain state for any tests which modify it!
|
||||
|
||||
async function referenceGetPartialAmountFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const product = numerator.mul(target);
|
||||
if (product.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
return product.dividedToIntegerBy(denominator);
|
||||
}
|
||||
|
||||
describe('addFillResults', async () => {
|
||||
function makeFillResults(value: BigNumber): FillResults {
|
||||
return {
|
||||
@ -159,18 +165,18 @@ describe('Exchange core internal functions', () => {
|
||||
// implementation or the Solidity implementation of
|
||||
// calculateFillResults.
|
||||
return {
|
||||
makerAssetFilledAmount: await referenceGetPartialAmountAsync(
|
||||
makerAssetFilledAmount: await referenceGetPartialAmountFloorAsync(
|
||||
takerAssetFilledAmount,
|
||||
orderTakerAssetAmount,
|
||||
otherAmount,
|
||||
),
|
||||
takerAssetFilledAmount,
|
||||
makerFeePaid: await referenceGetPartialAmountAsync(
|
||||
makerFeePaid: await referenceGetPartialAmountFloorAsync(
|
||||
takerAssetFilledAmount,
|
||||
orderTakerAssetAmount,
|
||||
otherAmount,
|
||||
),
|
||||
takerFeePaid: await referenceGetPartialAmountAsync(
|
||||
takerFeePaid: await referenceGetPartialAmountFloorAsync(
|
||||
takerAssetFilledAmount,
|
||||
orderTakerAssetAmount,
|
||||
otherAmount,
|
||||
@ -193,18 +199,55 @@ describe('Exchange core internal functions', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('getPartialAmount', async () => {
|
||||
async function testGetPartialAmountAsync(
|
||||
describe('getPartialAmountFloor', async () => {
|
||||
async function testGetPartialAmountFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
return testExchange.publicGetPartialAmount.callAsync(numerator, denominator, target);
|
||||
return testExchange.publicGetPartialAmountFloor.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'getPartialAmount',
|
||||
referenceGetPartialAmountAsync,
|
||||
testGetPartialAmountAsync,
|
||||
referenceGetPartialAmountFloorAsync,
|
||||
testGetPartialAmountFloorAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('getPartialAmountCeil', async () => {
|
||||
async function referenceGetPartialAmountCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const product = numerator.mul(target);
|
||||
const offset = product.add(denominator.sub(1));
|
||||
if (offset.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
const result = offset.dividedToIntegerBy(denominator);
|
||||
if (product.mod(denominator).eq(0)) {
|
||||
expect(result.mul(denominator)).to.be.bignumber.eq(product);
|
||||
} else {
|
||||
expect(result.mul(denominator)).to.be.bignumber.gt(product);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async function testGetPartialAmountCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
return testExchange.publicGetPartialAmountCeil.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'getPartialAmountCeil',
|
||||
referenceGetPartialAmountCeilAsync,
|
||||
testGetPartialAmountCeilAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@ -215,33 +258,33 @@ describe('Exchange core internal functions', () => {
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
const product = numerator.mul(target);
|
||||
if (denominator.eq(0)) {
|
||||
throw invalidOpcodeErrorForCall;
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const remainder = product.mod(denominator);
|
||||
if (remainder.eq(0)) {
|
||||
if (numerator.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
if (target.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
const product = numerator.mul(target);
|
||||
const remainder = product.mod(denominator);
|
||||
const remainderTimes1000 = remainder.mul('1000');
|
||||
const isError = remainderTimes1000.gt(product);
|
||||
if (product.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
if (product.eq(0)) {
|
||||
throw invalidOpcodeErrorForCall;
|
||||
}
|
||||
const remainderTimes1000000 = remainder.mul('1000000');
|
||||
if (remainderTimes1000000.greaterThan(MAX_UINT256)) {
|
||||
if (remainderTimes1000.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
const errPercentageTimes1000000 = remainderTimes1000000.dividedToIntegerBy(product);
|
||||
return errPercentageTimes1000000.greaterThan('1000');
|
||||
return isError;
|
||||
}
|
||||
async function testIsRoundingErrorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
return testExchange.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
return testExchange.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'isRoundingError',
|
||||
@ -251,6 +294,49 @@ describe('Exchange core internal functions', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('isRoundingErrorCeil', async () => {
|
||||
async function referenceIsRoundingErrorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
if (numerator.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
if (target.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
const product = numerator.mul(target);
|
||||
const remainder = product.mod(denominator);
|
||||
const error = denominator.sub(remainder).mod(denominator);
|
||||
const errorTimes1000 = error.mul('1000');
|
||||
const isError = errorTimes1000.gt(product);
|
||||
if (product.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
if (errorTimes1000.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
async function testIsRoundingErrorCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
return testExchange.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'isRoundingErrorCeil',
|
||||
referenceIsRoundingErrorAsync,
|
||||
testIsRoundingErrorCeilAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('updateFilledState', async () => {
|
||||
// Note(albrow): Since updateFilledState modifies the state by calling
|
||||
// sendTransaction, we must reset the state after each test.
|
||||
|
@ -71,20 +71,21 @@ describe('Exchange libs', () => {
|
||||
// combinatorial tests in test/exchange/internal. They test specific edge
|
||||
// cases that are not covered by the combinatorial tests.
|
||||
describe('LibMath', () => {
|
||||
it('should return false if there is a rounding error of 0.1%', async () => {
|
||||
describe('isRoundingError', () => {
|
||||
it('should return true if there is a rounding error of 0.1%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(999);
|
||||
const target = new BigNumber(50);
|
||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
it('should return false if there is a rounding of 0.09%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(9991);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
it('should return true if there is a rounding error of 0.11%', async () => {
|
||||
@ -92,10 +93,37 @@ describe('Exchange libs', () => {
|
||||
const denominator = new BigNumber(9989);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
});
|
||||
describe('isRoundingErrorCeil', () => {
|
||||
it('should return true if there is a rounding error of 0.1%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(1001);
|
||||
const target = new BigNumber(50);
|
||||
// rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1%
|
||||
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
it('should return false if there is a rounding of 0.09%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(10009);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09%
|
||||
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
it('should return true if there is a rounding error of 0.11%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(10011);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11%
|
||||
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('LibOrder', () => {
|
||||
describe('getOrderSchema', () => {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,11 +9,12 @@ import {
|
||||
TestSignatureValidatorContract,
|
||||
TestSignatureValidatorSignatureValidatorApprovalEventArgs,
|
||||
} from '../../generated_contract_wrappers/test_signature_validator';
|
||||
import { TestStaticCallReceiverContract } from '../../generated_contract_wrappers/test_static_call_receiver';
|
||||
import { ValidatorContract } from '../../generated_contract_wrappers/validator';
|
||||
import { WalletContract } from '../../generated_contract_wrappers/wallet';
|
||||
import { addressUtils } from '../utils/address_utils';
|
||||
import { artifacts } from '../utils/artifacts';
|
||||
import { expectContractCallFailed } from '../utils/assertions';
|
||||
import { expectContractCallFailed, expectContractCallFailedWithoutReasonAsync } from '../utils/assertions';
|
||||
import { chaiSetup } from '../utils/chai_setup';
|
||||
import { constants } from '../utils/constants';
|
||||
import { LogDecoder } from '../utils/log_decoder';
|
||||
@ -31,6 +32,8 @@ describe('MixinSignatureValidator', () => {
|
||||
let signatureValidator: TestSignatureValidatorContract;
|
||||
let testWallet: WalletContract;
|
||||
let testValidator: ValidatorContract;
|
||||
let maliciousWallet: TestStaticCallReceiverContract;
|
||||
let maliciousValidator: TestStaticCallReceiverContract;
|
||||
let signerAddress: string;
|
||||
let signerPrivateKey: Buffer;
|
||||
let notSignerAddress: string;
|
||||
@ -65,6 +68,11 @@ describe('MixinSignatureValidator', () => {
|
||||
txDefaults,
|
||||
signerAddress,
|
||||
);
|
||||
maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestStaticCallReceiver,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
signatureValidatorLogDecoder = new LogDecoder(web3Wrapper);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(testValidator.address, true, {
|
||||
@ -72,6 +80,16 @@ describe('MixinSignatureValidator', () => {
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
|
||||
maliciousValidator.address,
|
||||
true,
|
||||
{
|
||||
from: signerAddress,
|
||||
},
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
@ -263,32 +281,6 @@ describe('MixinSignatureValidator', () => {
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=Caller and signer is caller', async () => {
|
||||
const signature = ethUtil.toBuffer(`0x${SignatureType.Caller}`);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||
orderHashHex,
|
||||
signerAddress,
|
||||
signatureHex,
|
||||
{ from: signerAddress },
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=Caller and signer is not caller', async () => {
|
||||
const signature = ethUtil.toBuffer(`0x${SignatureType.Caller}`);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||
orderHashHex,
|
||||
signerAddress,
|
||||
signatureHex,
|
||||
{ from: notSignerAddress },
|
||||
);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=Wallet and signature is valid', async () => {
|
||||
// Create EIP712 signature
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
@ -334,6 +326,29 @@ describe('MixinSignatureValidator', () => {
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should revert when `isValidSignature` attempts to update state and SignatureType=Wallet', async () => {
|
||||
// Create EIP712 signature
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
|
||||
const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
|
||||
// Create 0x signature from EIP712 signature
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(ecSignature.v),
|
||||
ecSignature.r,
|
||||
ecSignature.s,
|
||||
ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
await expectContractCallFailed(
|
||||
signatureValidator.publicIsValidSignature.callAsync(
|
||||
orderHashHex,
|
||||
maliciousWallet.address,
|
||||
signatureHex,
|
||||
),
|
||||
RevertReason.WalletError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => {
|
||||
const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
|
||||
const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
|
||||
@ -364,6 +379,17 @@ describe('MixinSignatureValidator', () => {
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should revert when `isValidSignature` attempts to update state and SignatureType=Validator', async () => {
|
||||
const validatorAddress = ethUtil.toBuffer(`${maliciousValidator.address}`);
|
||||
const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
|
||||
const signature = Buffer.concat([validatorAddress, signatureType]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
await expectContractCallFailed(
|
||||
signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex),
|
||||
RevertReason.ValidatorError,
|
||||
);
|
||||
});
|
||||
it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => {
|
||||
// Set approval of signature validator to false
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
@ -388,53 +414,6 @@ describe('MixinSignatureValidator', () => {
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=Trezor and signature is valid', async () => {
|
||||
// Create Trezor signature
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const orderHashWithTrezorPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex, SignerType.Trezor);
|
||||
const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex);
|
||||
const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey);
|
||||
// Create 0x signature from Trezor signature
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(ecSignature.v),
|
||||
ecSignature.r,
|
||||
ecSignature.s,
|
||||
ethUtil.toBuffer(`0x${SignatureType.Trezor}`),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||
orderHashHex,
|
||||
signerAddress,
|
||||
signatureHex,
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=Trezor and signature is invalid', async () => {
|
||||
// Create Trezor signature
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const orderHashWithTrezorPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex, SignerType.Trezor);
|
||||
const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex);
|
||||
const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey);
|
||||
// Create 0x signature from Trezor signature
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(ecSignature.v),
|
||||
ecSignature.r,
|
||||
ecSignature.s,
|
||||
ethUtil.toBuffer(`0x${SignatureType.Trezor}`),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature.
|
||||
// This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress`
|
||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||
orderHashHex,
|
||||
notSignerAddress,
|
||||
signatureHex,
|
||||
);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=Presigned and signer has presigned hash', async () => {
|
||||
// Presign hash
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
@ -468,6 +447,42 @@ describe('MixinSignatureValidator', () => {
|
||||
);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true when message was signed by a Trezor One (firmware version 1.6.2)', async () => {
|
||||
// messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
|
||||
const signer = '0xc28b145f10f0bcf0fc000e778615f8fd73490bad';
|
||||
const v = ethUtil.toBuffer('0x1c');
|
||||
const r = ethUtil.toBuffer('0x7b888b596ccf87f0bacab0dcb483124973f7420f169b4824d7a12534ac1e9832');
|
||||
const s = ethUtil.toBuffer('0x0c8e14f7edc01459e13965f1da56e0c23ed11e2cca932571eee1292178f90424');
|
||||
const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
|
||||
const signature = Buffer.concat([v, r, s, trezorSignatureType]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||
messageHash,
|
||||
signer,
|
||||
signatureHex,
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return true when message was signed by a Trezor Model T (firmware version 2.0.7)', async () => {
|
||||
// messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
|
||||
const signer = '0x98ce6d9345e8ffa7d99ee0822272fae9d2c0e895';
|
||||
const v = ethUtil.toBuffer('0x1c');
|
||||
const r = ethUtil.toBuffer('0x423b71062c327f0ec4fe199b8da0f34185e59b4c1cb4cc23df86cac4a601fb3f');
|
||||
const s = ethUtil.toBuffer('0x53810d6591b5348b7ee08ee812c874b0fdfb942c9849d59512c90e295221091f');
|
||||
const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
|
||||
const signature = Buffer.concat([v, r, s, trezorSignatureType]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||
messageHash,
|
||||
signer,
|
||||
signatureHex,
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSignatureValidatorApproval', () => {
|
||||
|
@ -11,6 +11,7 @@ import { DummyERC721TokenContract } from '../../generated_contract_wrappers/dumm
|
||||
import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy';
|
||||
import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy';
|
||||
import { ExchangeContract } from '../../generated_contract_wrappers/exchange';
|
||||
import { ReentrantERC20TokenContract } from '../../generated_contract_wrappers/reentrant_erc20_token';
|
||||
import { artifacts } from '../utils/artifacts';
|
||||
import { expectTransactionFailedAsync } from '../utils/assertions';
|
||||
import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
|
||||
@ -40,6 +41,7 @@ describe('Exchange wrappers', () => {
|
||||
let exchange: ExchangeContract;
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
let erc721Proxy: ERC721ProxyContract;
|
||||
let reentrantErc20Token: ReentrantERC20TokenContract;
|
||||
|
||||
let exchangeWrapper: ExchangeWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
@ -104,6 +106,13 @@ describe('Exchange wrappers', () => {
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ReentrantERC20Token,
|
||||
provider,
|
||||
txDefaults,
|
||||
exchange.address,
|
||||
);
|
||||
|
||||
defaultMakerAssetAddress = erc20TokenA.address;
|
||||
defaultTakerAssetAddress = erc20TokenB.address;
|
||||
|
||||
@ -126,6 +135,26 @@ describe('Exchange wrappers', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('fillOrKillOrder', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow fillOrKillOrder to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
|
||||
RevertReason.TransferFailed,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('fillOrKillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should transfer the correct amounts', async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
@ -197,6 +226,25 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('fillOrderNoThrow', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow fillOrderNoThrow to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(erc20Balances).to.deep.equal(newBalances);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('fillOrderNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should transfer the correct amounts', async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
@ -397,6 +445,26 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('batchFillOrders', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow batchFillOrders to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.batchFillOrdersAsync([signedOrder], takerAddress),
|
||||
RevertReason.TransferFailed,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('batchFillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should transfer the correct amounts', async () => {
|
||||
const takerAssetFillAmounts: BigNumber[] = [];
|
||||
const makerAssetAddress = erc20TokenA.address;
|
||||
@ -446,6 +514,26 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('batchFillOrKillOrders', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow batchFillOrKillOrders to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.batchFillOrKillOrdersAsync([signedOrder], takerAddress),
|
||||
RevertReason.TransferFailed,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('batchFillOrKillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should transfer the correct amounts', async () => {
|
||||
const takerAssetFillAmounts: BigNumber[] = [];
|
||||
const makerAssetAddress = erc20TokenA.address;
|
||||
@ -512,6 +600,25 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('batchFillOrdersNoThrow', async () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow batchFillOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await exchangeWrapper.batchFillOrdersNoThrowAsync([signedOrder], takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(erc20Balances).to.deep.equal(newBalances);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('batchFillOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should transfer the correct amounts', async () => {
|
||||
const takerAssetFillAmounts: BigNumber[] = [];
|
||||
const makerAssetAddress = erc20TokenA.address;
|
||||
@ -625,6 +732,28 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('marketSellOrders', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow marketSellOrders to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, {
|
||||
takerAssetFillAmount: signedOrder.takerAssetAmount,
|
||||
}),
|
||||
RevertReason.TransferFailed,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('marketSellOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should stop when the entire takerAssetFillAmount is filled', async () => {
|
||||
const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
|
||||
signedOrders[1].takerAssetAmount.div(2),
|
||||
@ -717,6 +846,27 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('marketSellOrdersNoThrow', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow marketSellOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await exchangeWrapper.marketSellOrdersNoThrowAsync([signedOrder], takerAddress, {
|
||||
takerAssetFillAmount: signedOrder.takerAssetAmount,
|
||||
});
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(erc20Balances).to.deep.equal(newBalances);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('marketSellOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should stop when the entire takerAssetFillAmount is filled', async () => {
|
||||
const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
|
||||
signedOrders[1].takerAssetAmount.div(2),
|
||||
@ -843,6 +993,28 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('marketBuyOrders', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow marketBuyOrders to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, {
|
||||
makerAssetFillAmount: signedOrder.makerAssetAmount,
|
||||
}),
|
||||
RevertReason.TransferFailed,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('marketBuyOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should stop when the entire makerAssetFillAmount is filled', async () => {
|
||||
const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
|
||||
signedOrders[1].makerAssetAmount.div(2),
|
||||
@ -933,6 +1105,27 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
|
||||
describe('marketBuyOrdersNoThrow', () => {
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow marketBuyOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
|
||||
it(description, async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await exchangeWrapper.marketBuyOrdersNoThrowAsync([signedOrder], takerAddress, {
|
||||
makerAssetFillAmount: signedOrder.makerAssetAmount,
|
||||
});
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(erc20Balances).to.deep.equal(newBalances);
|
||||
});
|
||||
});
|
||||
};
|
||||
describe('marketBuyOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
|
||||
|
||||
it('should stop when the entire makerAssetFillAmount is filled', async () => {
|
||||
const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
|
||||
signedOrders[1].makerAssetAmount.div(2),
|
||||
|
@ -16,6 +16,7 @@ import * as MixinAuthorizable from '../../artifacts/MixinAuthorizable.json';
|
||||
import * as MultiSigWallet from '../../artifacts/MultiSigWallet.json';
|
||||
import * as MultiSigWalletWithTimeLock from '../../artifacts/MultiSigWalletWithTimeLock.json';
|
||||
import * as OrderValidator from '../../artifacts/OrderValidator.json';
|
||||
import * as ReentrantERC20Token from '../../artifacts/ReentrantERC20Token.json';
|
||||
import * as TestAssetProxyDispatcher from '../../artifacts/TestAssetProxyDispatcher.json';
|
||||
import * as TestAssetProxyOwner from '../../artifacts/TestAssetProxyOwner.json';
|
||||
import * as TestConstants from '../../artifacts/TestConstants.json';
|
||||
@ -23,6 +24,7 @@ import * as TestExchangeInternals from '../../artifacts/TestExchangeInternals.js
|
||||
import * as TestLibBytes from '../../artifacts/TestLibBytes.json';
|
||||
import * as TestLibs from '../../artifacts/TestLibs.json';
|
||||
import * as TestSignatureValidator from '../../artifacts/TestSignatureValidator.json';
|
||||
import * as TestStaticCallReceiver from '../../artifacts/TestStaticCallReceiver.json';
|
||||
import * as TokenRegistry from '../../artifacts/TokenRegistry.json';
|
||||
import * as Validator from '../../artifacts/Validator.json';
|
||||
import * as Wallet from '../../artifacts/Wallet.json';
|
||||
@ -48,6 +50,7 @@ export const artifacts = {
|
||||
MultiSigWallet: (MultiSigWallet as any) as ContractArtifact,
|
||||
MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
|
||||
OrderValidator: (OrderValidator as any) as ContractArtifact,
|
||||
ReentrantERC20Token: (ReentrantERC20Token as any) as ContractArtifact,
|
||||
TestAssetProxyOwner: (TestAssetProxyOwner as any) as ContractArtifact,
|
||||
TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact,
|
||||
TestConstants: (TestConstants as any) as ContractArtifact,
|
||||
@ -55,6 +58,7 @@ export const artifacts = {
|
||||
TestLibs: (TestLibs as any) as ContractArtifact,
|
||||
TestExchangeInternals: (TestExchangeInternals as any) as ContractArtifact,
|
||||
TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact,
|
||||
TestStaticCallReceiver: (TestStaticCallReceiver as any) as ContractArtifact,
|
||||
Validator: (Validator as any) as ContractArtifact,
|
||||
Wallet: (Wallet as any) as ContractArtifact,
|
||||
TokenRegistry: (TokenRegistry as any) as ContractArtifact,
|
||||
|
@ -51,4 +51,16 @@ export const constants = {
|
||||
WORD_LENGTH: 32,
|
||||
ZERO_AMOUNT: new BigNumber(0),
|
||||
PERCENTAGE_DENOMINATOR: new BigNumber(10).pow(18),
|
||||
FUNCTIONS_WITH_MUTEX: [
|
||||
'FILL_ORDER',
|
||||
'FILL_OR_KILL_ORDER',
|
||||
'BATCH_FILL_ORDERS',
|
||||
'BATCH_FILL_OR_KILL_ORDERS',
|
||||
'MARKET_BUY_ORDERS',
|
||||
'MARKET_SELL_ORDERS',
|
||||
'MATCH_ORDERS',
|
||||
'CANCEL_ORDER',
|
||||
'CANCEL_ORDERS_UP_TO',
|
||||
'SET_SIGNATURE_VALIDATOR_APPROVAL',
|
||||
],
|
||||
};
|
||||
|
@ -467,17 +467,17 @@ export class FillOrderCombinatorialUtils {
|
||||
? remainingTakerAmountToFill
|
||||
: alreadyFilledTakerAmount.add(takerAssetFillAmount);
|
||||
|
||||
const expFilledMakerAmount = orderUtils.getPartialAmount(
|
||||
const expFilledMakerAmount = orderUtils.getPartialAmountFloor(
|
||||
expFilledTakerAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
);
|
||||
const expMakerFeePaid = orderUtils.getPartialAmount(
|
||||
const expMakerFeePaid = orderUtils.getPartialAmountFloor(
|
||||
expFilledTakerAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerFee,
|
||||
);
|
||||
const expTakerFeePaid = orderUtils.getPartialAmount(
|
||||
const expTakerFeePaid = orderUtils.getPartialAmountFloor(
|
||||
expFilledTakerAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.takerFee,
|
||||
@ -668,7 +668,7 @@ export class FillOrderCombinatorialUtils {
|
||||
signedOrder: SignedOrder,
|
||||
takerAssetFillAmount: BigNumber,
|
||||
): Promise<void> {
|
||||
const makerAssetFillAmount = orderUtils.getPartialAmount(
|
||||
const makerAssetFillAmount = orderUtils.getPartialAmountFloor(
|
||||
takerAssetFillAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
@ -705,7 +705,7 @@ export class FillOrderCombinatorialUtils {
|
||||
);
|
||||
}
|
||||
|
||||
const makerFee = orderUtils.getPartialAmount(
|
||||
const makerFee = orderUtils.getPartialAmountFloor(
|
||||
takerAssetFillAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerFee,
|
||||
@ -829,7 +829,7 @@ export class FillOrderCombinatorialUtils {
|
||||
);
|
||||
}
|
||||
|
||||
const takerFee = orderUtils.getPartialAmount(
|
||||
const takerFee = orderUtils.getPartialAmountFloor(
|
||||
takerAssetFillAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.takerFee,
|
||||
|
@ -4,11 +4,20 @@ import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types';
|
||||
|
||||
import { chaiSetup } from './chai_setup';
|
||||
import { ERC20Wrapper } from './erc20_wrapper';
|
||||
import { ERC721Wrapper } from './erc721_wrapper';
|
||||
import { ExchangeWrapper } from './exchange_wrapper';
|
||||
import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts } from './types';
|
||||
import {
|
||||
ERC20BalancesByOwner,
|
||||
ERC721TokenIdsByOwner,
|
||||
OrderInfo,
|
||||
OrderStatus,
|
||||
TransferAmountsByMatchOrders as TransferAmounts,
|
||||
TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts,
|
||||
} from './types';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@ -18,43 +27,107 @@ export class MatchOrderTester {
|
||||
private readonly _erc20Wrapper: ERC20Wrapper;
|
||||
private readonly _erc721Wrapper: ERC721Wrapper;
|
||||
private readonly _feeTokenAddress: string;
|
||||
|
||||
/// @dev Compares a pair of ERC20 balances and a pair of ERC721 token owners.
|
||||
/// @param expectedNewERC20BalancesByOwner Expected ERC20 balances.
|
||||
/// @param realERC20BalancesByOwner Actual ERC20 balances.
|
||||
/// @param expectedNewERC721TokenIdsByOwner Expected ERC721 token owners.
|
||||
/// @param realERC721TokenIdsByOwner Actual ERC20 token owners.
|
||||
/// @return True only if ERC20 balances match and ERC721 token owners match.
|
||||
private static _compareExpectedAndRealBalances(
|
||||
expectedNewERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
realERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
expectedNewERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
): boolean {
|
||||
// ERC20 Balances
|
||||
const doesErc20BalancesMatch = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner);
|
||||
if (!doesErc20BalancesMatch) {
|
||||
return false;
|
||||
/// @dev Checks values from the logs produced by Exchange.matchOrders against the expected transfer amounts.
|
||||
/// Values include the amounts transferred from the left/right makers and taker, along with
|
||||
/// the fees paid on each matched order. These are also the return values of MatchOrders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders.
|
||||
/// @param takerAddress Address of taker (account that called Exchange.matchOrders)
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
private static async _assertLogsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
transactionReceipt: TransactionReceiptWithDecodedLogs,
|
||||
takerAddress: string,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
): Promise<void> {
|
||||
// Should have two fill event logs -- one for each order.
|
||||
const transactionFillLogs = _.filter(transactionReceipt.logs, ['event', 'Fill']);
|
||||
expect(transactionFillLogs.length, 'Checking number of logs').to.be.equal(2);
|
||||
// First log is for left fill
|
||||
const leftLog = (transactionFillLogs[0] as any).args as LoggedTransferAmounts;
|
||||
expect(leftLog.makerAddress, 'Checking logged maker address of left order').to.be.equal(
|
||||
signedOrderLeft.makerAddress,
|
||||
);
|
||||
expect(leftLog.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress);
|
||||
const amountBoughtByLeftMaker = new BigNumber(leftLog.takerAssetFilledAmount);
|
||||
const amountSoldByLeftMaker = new BigNumber(leftLog.makerAssetFilledAmount);
|
||||
const feePaidByLeftMaker = new BigNumber(leftLog.makerFeePaid);
|
||||
const feePaidByTakerLeft = new BigNumber(leftLog.takerFeePaid);
|
||||
// Second log is for right fill
|
||||
const rightLog = (transactionFillLogs[1] as any).args as LoggedTransferAmounts;
|
||||
expect(rightLog.makerAddress, 'Checking logged maker address of right order').to.be.equal(
|
||||
signedOrderRight.makerAddress,
|
||||
);
|
||||
expect(rightLog.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress);
|
||||
const amountBoughtByRightMaker = new BigNumber(rightLog.takerAssetFilledAmount);
|
||||
const amountSoldByRightMaker = new BigNumber(rightLog.makerAssetFilledAmount);
|
||||
const feePaidByRightMaker = new BigNumber(rightLog.makerFeePaid);
|
||||
const feePaidByTakerRight = new BigNumber(rightLog.takerFeePaid);
|
||||
// Derive amount received by taker
|
||||
const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker);
|
||||
// Assert log values - left order
|
||||
expect(amountBoughtByLeftMaker, 'Checking logged amount bought by left maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||
);
|
||||
expect(amountSoldByLeftMaker, 'Checking logged amount sold by left maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountSoldByLeftMaker,
|
||||
);
|
||||
expect(feePaidByLeftMaker, 'Checking logged fee paid by left maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByLeftMaker,
|
||||
);
|
||||
expect(feePaidByTakerLeft, 'Checking logged fee paid on left order by taker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByTakerLeft,
|
||||
);
|
||||
// Assert log values - right order
|
||||
expect(amountBoughtByRightMaker, 'Checking logged amount bought by right maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||
);
|
||||
expect(amountSoldByRightMaker, 'Checking logged amount sold by right maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountSoldByRightMaker,
|
||||
);
|
||||
expect(feePaidByRightMaker, 'Checking logged fee paid by right maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByRightMaker,
|
||||
);
|
||||
expect(feePaidByTakerRight, 'Checking logged fee paid on right order by taker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByTakerRight,
|
||||
);
|
||||
// Assert derived amount received by taker
|
||||
expect(amountReceivedByTaker, 'Checking logged amount received by taker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountReceivedByTaker,
|
||||
);
|
||||
}
|
||||
/// @dev Asserts all expected ERC20 and ERC721 account holdings match the real holdings.
|
||||
/// @param expectedERC20BalancesByOwner Expected ERC20 balances.
|
||||
/// @param realERC20BalancesByOwner Real ERC20 balances.
|
||||
/// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
|
||||
/// @param realERC721TokenIdsByOwner Real ERC20 token owners.
|
||||
private static async _assertAllKnownBalancesAsync(
|
||||
expectedERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
realERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
): Promise<void> {
|
||||
// ERC20 Balances
|
||||
const areERC20BalancesEqual = _.isEqual(expectedERC20BalancesByOwner, realERC20BalancesByOwner);
|
||||
expect(areERC20BalancesEqual, 'Checking all known ERC20 account balances').to.be.true();
|
||||
// ERC721 Token Ids
|
||||
const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(
|
||||
expectedNewERC721TokenIdsByOwner,
|
||||
tokenIdsByOwner => {
|
||||
const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(expectedERC721TokenIdsByOwner, tokenIdsByOwner => {
|
||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
||||
_.sortBy(tokenIds);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => {
|
||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
||||
_.sortBy(tokenIds);
|
||||
});
|
||||
});
|
||||
const doesErc721TokenIdsMatch = _.isEqual(
|
||||
const areERC721TokenIdsEqual = _.isEqual(
|
||||
sortedExpectedNewERC721TokenIdsByOwner,
|
||||
sortedNewERC721TokenIdsByOwner,
|
||||
);
|
||||
return doesErc721TokenIdsMatch;
|
||||
expect(areERC721TokenIdsEqual, 'Checking all known ERC721 account balances').to.be.true();
|
||||
}
|
||||
/// @dev Constructs new MatchOrderTester.
|
||||
/// @param exchangeWrapper Used to call to the Exchange.
|
||||
@ -72,150 +145,199 @@ export class MatchOrderTester {
|
||||
this._erc721Wrapper = erc721Wrapper;
|
||||
this._feeTokenAddress = feeTokenAddress;
|
||||
}
|
||||
/// @dev Matches two complementary orders and validates results.
|
||||
/// Validation either succeeds or throws.
|
||||
/// @dev Matches two complementary orders and asserts results.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param takerAddress Address of taker (the address who matched the two orders)
|
||||
/// @param erc20BalancesByOwner Current ERC20 balances.
|
||||
/// @param erc721TokenIdsByOwner Current ERC721 token owners.
|
||||
/// @param initialTakerAssetFilledAmountLeft Current amount the left order has been filled.
|
||||
/// @param initialTakerAssetFilledAmountRight Current amount the right order has been filled.
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
/// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
|
||||
/// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
|
||||
/// @return New ERC20 balances & ERC721 token owners.
|
||||
public async matchOrdersAndVerifyBalancesAsync(
|
||||
public async matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
takerAddress: string,
|
||||
erc20BalancesByOwner: ERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
initialTakerAssetFilledAmountLeft?: BigNumber,
|
||||
initialTakerAssetFilledAmountRight?: BigNumber,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
initialLeftOrderFilledAmount: BigNumber = new BigNumber(0),
|
||||
initialRightOrderFilledAmount: BigNumber = new BigNumber(0),
|
||||
): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> {
|
||||
// Verify Left order preconditions
|
||||
// Assert initial order states
|
||||
await this._assertInitialOrderStatesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
initialLeftOrderFilledAmount,
|
||||
initialRightOrderFilledAmount,
|
||||
);
|
||||
// Match left & right orders
|
||||
const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
);
|
||||
const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync();
|
||||
const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync();
|
||||
// Assert logs
|
||||
await MatchOrderTester._assertLogsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
transactionReceipt,
|
||||
takerAddress,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Assert exchange state
|
||||
await this._assertExchangeStateAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
initialLeftOrderFilledAmount,
|
||||
initialRightOrderFilledAmount,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Assert balances of makers, taker, and fee recipients
|
||||
await this._assertBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
newERC20BalancesByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
takerAddress,
|
||||
);
|
||||
return [newERC20BalancesByOwner, newERC721TokenIdsByOwner];
|
||||
}
|
||||
/// @dev Asserts initial exchange state for the left and right orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param expectedOrderFilledAmountLeft How much left order has been filled, prior to matching orders.
|
||||
/// @param expectedOrderFilledAmountRight How much the right order has been filled, prior to matching orders.
|
||||
private async _assertInitialOrderStatesAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
expectedOrderFilledAmountLeft: BigNumber,
|
||||
expectedOrderFilledAmountRight: BigNumber,
|
||||
): Promise<void> {
|
||||
// Assert left order initial state
|
||||
const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||
);
|
||||
const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft
|
||||
? initialTakerAssetFilledAmountLeft
|
||||
: new BigNumber(0);
|
||||
expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft);
|
||||
// Verify Right order preconditions
|
||||
expect(orderTakerAssetFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal(
|
||||
expectedOrderFilledAmountLeft,
|
||||
);
|
||||
// Assert right order initial state
|
||||
const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight
|
||||
? initialTakerAssetFilledAmountRight
|
||||
: new BigNumber(0);
|
||||
expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight);
|
||||
// Match left & right orders
|
||||
await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
|
||||
const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync();
|
||||
const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync();
|
||||
// Calculate expected balance changes
|
||||
const expectedTransferAmounts = await this._calculateExpectedTransferAmountsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
orderTakerAssetFilledAmountLeft,
|
||||
orderTakerAssetFilledAmountRight,
|
||||
expect(orderTakerAssetFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal(
|
||||
expectedOrderFilledAmountRight,
|
||||
);
|
||||
}
|
||||
/// @dev Asserts the exchange state against the expected amounts transferred by from matching orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
|
||||
/// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
|
||||
/// @return TransferAmounts A struct containing the expected transfer amounts.
|
||||
private async _assertExchangeStateAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
initialLeftOrderFilledAmount: BigNumber,
|
||||
initialRightOrderFilledAmount: BigNumber,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
): Promise<void> {
|
||||
// Assert state for left order: amount bought by left maker
|
||||
let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||
);
|
||||
amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(initialLeftOrderFilledAmount);
|
||||
expect(amountBoughtByLeftMaker, 'Checking exchange state for left order').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||
);
|
||||
// Assert state for right order: amount bought by right maker
|
||||
let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
amountBoughtByRightMaker = amountBoughtByRightMaker.minus(initialRightOrderFilledAmount);
|
||||
expect(amountBoughtByRightMaker, 'Checking exchange state for right order').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||
);
|
||||
// Assert left order status
|
||||
const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount);
|
||||
const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker)
|
||||
? OrderStatus.FULLY_FILLED
|
||||
: OrderStatus.FILLABLE;
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for left order').to.be.equal(
|
||||
leftExpectedStatus,
|
||||
);
|
||||
// Assert right order status
|
||||
const maxAmountBoughtByRightMaker = signedOrderRight.takerAssetAmount.minus(initialRightOrderFilledAmount);
|
||||
const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker)
|
||||
? OrderStatus.FULLY_FILLED
|
||||
: OrderStatus.FILLABLE;
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for right order').to.be.equal(
|
||||
rightExpectedStatus,
|
||||
);
|
||||
}
|
||||
/// @dev Asserts account balances after matching orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param initialERC20BalancesByOwner ERC20 balances prior to order matching.
|
||||
/// @param initialERC721TokenIdsByOwner ERC721 token owners prior to order matching.
|
||||
/// @param finalERC20BalancesByOwner ERC20 balances after order matching.
|
||||
/// @param finalERC721TokenIdsByOwner ERC721 token owners after order matching.
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
/// @param takerAddress Address of taker (account that called Exchange.matchOrders).
|
||||
private async _assertBalancesAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
initialERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
finalERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
takerAddress: string,
|
||||
): Promise<void> {
|
||||
let expectedERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
[expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
initialERC20BalancesByOwner,
|
||||
initialERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Assert our expected balances are equal to the actual balances
|
||||
const didExpectedBalancesMatchRealBalances = MatchOrderTester._compareExpectedAndRealBalances(
|
||||
// Assert balances of makers, taker, and fee recipients
|
||||
await this._assertMakerTakerAndFeeRecipientBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
expectedERC20BalancesByOwner,
|
||||
newERC20BalancesByOwner,
|
||||
finalERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
finalERC721TokenIdsByOwner,
|
||||
takerAddress,
|
||||
);
|
||||
expect(didExpectedBalancesMatchRealBalances).to.be.true();
|
||||
return [newERC20BalancesByOwner, newERC721TokenIdsByOwner];
|
||||
}
|
||||
/// @dev Calculates expected transfer amounts between order makers, fee recipients, and
|
||||
/// the taker when two orders are matched.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders.
|
||||
/// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders.
|
||||
/// @return TransferAmounts A struct containing the expected transfer amounts.
|
||||
private async _calculateExpectedTransferAmountsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
orderTakerAssetFilledAmountLeft: BigNumber,
|
||||
orderTakerAssetFilledAmountRight: BigNumber,
|
||||
): Promise<TransferAmounts> {
|
||||
let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||
// Assert balances for all known accounts
|
||||
await MatchOrderTester._assertAllKnownBalancesAsync(
|
||||
expectedERC20BalancesByOwner,
|
||||
finalERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner,
|
||||
finalERC721TokenIdsByOwner,
|
||||
);
|
||||
amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft);
|
||||
const amountSoldByLeftMaker = amountBoughtByLeftMaker
|
||||
.times(signedOrderLeft.makerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderLeft.takerAssetAmount);
|
||||
const amountReceivedByRightMaker = amountBoughtByLeftMaker
|
||||
.times(signedOrderRight.takerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const amountReceivedByTaker = amountSoldByLeftMaker.minus(amountReceivedByRightMaker);
|
||||
let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight);
|
||||
const amountSoldByRightMaker = amountBoughtByRightMaker
|
||||
.times(signedOrderRight.makerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderRight.takerAssetAmount);
|
||||
const amountReceivedByLeftMaker = amountSoldByRightMaker;
|
||||
const feePaidByLeftMaker = signedOrderLeft.makerFee
|
||||
.times(amountSoldByLeftMaker)
|
||||
.dividedToIntegerBy(signedOrderLeft.makerAssetAmount);
|
||||
const feePaidByRightMaker = signedOrderRight.makerFee
|
||||
.times(amountSoldByRightMaker)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const feePaidByTakerLeft = signedOrderLeft.takerFee
|
||||
.times(amountSoldByLeftMaker)
|
||||
.dividedToIntegerBy(signedOrderLeft.makerAssetAmount);
|
||||
const feePaidByTakerRight = signedOrderRight.takerFee
|
||||
.times(amountSoldByRightMaker)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const totalFeePaidByTaker = feePaidByTakerLeft.add(feePaidByTakerRight);
|
||||
const feeReceivedLeft = feePaidByLeftMaker.add(feePaidByTakerLeft);
|
||||
const feeReceivedRight = feePaidByRightMaker.add(feePaidByTakerRight);
|
||||
// Return values
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountBoughtByLeftMaker,
|
||||
amountSoldByLeftMaker,
|
||||
amountReceivedByLeftMaker,
|
||||
feePaidByLeftMaker,
|
||||
// Right Maker
|
||||
amountBoughtByRightMaker,
|
||||
amountSoldByRightMaker,
|
||||
amountReceivedByRightMaker,
|
||||
feePaidByRightMaker,
|
||||
// Taker
|
||||
amountReceivedByTaker,
|
||||
feePaidByTakerLeft,
|
||||
feePaidByTakerRight,
|
||||
totalFeePaidByTaker,
|
||||
// Fee Recipients
|
||||
feeReceivedLeft,
|
||||
feeReceivedRight,
|
||||
};
|
||||
return expectedTransferAmounts;
|
||||
}
|
||||
/// @dev Calculates the expected balances of order makers, fee recipients, and the taker,
|
||||
/// as a result of matching two orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param takerAddress Address of taker (the address who matched the two orders)
|
||||
/// @param erc20BalancesByOwner Current ERC20 balances.
|
||||
/// @param erc721TokenIdsByOwner Current ERC721 token owners.
|
||||
/// @param expectedTransferAmounts A struct containing the expected transfer amounts.
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
/// @return Expected ERC20 balances & ERC721 token owners after orders have been matched.
|
||||
private _calculateExpectedBalances(
|
||||
signedOrderLeft: SignedOrder,
|
||||
@ -247,7 +369,7 @@ export class MatchOrderTester {
|
||||
expectedNewERC20BalancesByOwner[makerAddressRight][
|
||||
takerAssetAddressRight
|
||||
] = expectedNewERC20BalancesByOwner[makerAddressRight][takerAssetAddressRight].add(
|
||||
expectedTransferAmounts.amountReceivedByRightMaker,
|
||||
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||
);
|
||||
// Taker
|
||||
expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
@ -277,7 +399,7 @@ export class MatchOrderTester {
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
makerAddressLeft
|
||||
][takerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByLeftMaker);
|
||||
][takerAssetAddressLeft].add(expectedTransferAmounts.amountBoughtByLeftMaker);
|
||||
// Right Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressRight][
|
||||
makerAssetAddressRight
|
||||
@ -307,20 +429,138 @@ export class MatchOrderTester {
|
||||
// Taker Fees
|
||||
expectedNewERC20BalancesByOwner[takerAddress][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
|
||||
takerAddress
|
||||
][this._feeTokenAddress].minus(expectedTransferAmounts.totalFeePaidByTaker);
|
||||
][this._feeTokenAddress].minus(
|
||||
expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight),
|
||||
);
|
||||
// Left Fee Recipient Fees
|
||||
expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][
|
||||
this._feeTokenAddress
|
||||
] = expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][this._feeTokenAddress].add(
|
||||
expectedTransferAmounts.feeReceivedLeft,
|
||||
expectedTransferAmounts.feePaidByLeftMaker.add(expectedTransferAmounts.feePaidByTakerLeft),
|
||||
);
|
||||
// Right Fee Recipient Fees
|
||||
expectedNewERC20BalancesByOwner[feeRecipientAddressRight][
|
||||
this._feeTokenAddress
|
||||
] = expectedNewERC20BalancesByOwner[feeRecipientAddressRight][this._feeTokenAddress].add(
|
||||
expectedTransferAmounts.feeReceivedRight,
|
||||
expectedTransferAmounts.feePaidByRightMaker.add(expectedTransferAmounts.feePaidByTakerRight),
|
||||
);
|
||||
|
||||
return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner];
|
||||
}
|
||||
}
|
||||
/// @dev Asserts ERC20 account balances and ERC721 token holdings that result from order matching.
|
||||
/// Specifically checks balances of makers, taker and fee recipients.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param expectedERC20BalancesByOwner Expected ERC20 balances.
|
||||
/// @param realERC20BalancesByOwner Real ERC20 balances.
|
||||
/// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
|
||||
/// @param realERC721TokenIdsByOwner Real ERC20 token owners.
|
||||
/// @param takerAddress Address of taker (account that called Exchange.matchOrders).
|
||||
private async _assertMakerTakerAndFeeRecipientBalancesAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
expectedERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
realERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
takerAddress: string,
|
||||
): Promise<void> {
|
||||
// Individual balance comparisons
|
||||
const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData);
|
||||
const makerERC20AssetDataLeft =
|
||||
makerAssetProxyIdLeft === AssetProxyId.ERC20
|
||||
? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData)
|
||||
: assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress;
|
||||
const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData);
|
||||
const makerERC20AssetDataRight =
|
||||
makerAssetProxyIdRight === AssetProxyId.ERC20
|
||||
? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData)
|
||||
: assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
|
||||
const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress;
|
||||
if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft],
|
||||
'Checking left maker egress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft],
|
||||
'Checking right maker ingress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft],
|
||||
'Checking taker ingress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]);
|
||||
} else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
|
||||
'Checking left maker egress ERC721 account holdings',
|
||||
).to.be.deep.equal(
|
||||
expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
|
||||
);
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
|
||||
'Checking right maker ERC721 account holdings',
|
||||
).to.be.deep.equal(
|
||||
expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
|
||||
);
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(),
|
||||
'Checking taker ingress ERC721 account holdings',
|
||||
).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort());
|
||||
} else {
|
||||
throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`);
|
||||
}
|
||||
if (makerAssetProxyIdRight === AssetProxyId.ERC20) {
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight],
|
||||
'Checking left maker ingress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
|
||||
'Checking right maker egress ERC20 account balance',
|
||||
).to.be.bignumber.equal(
|
||||
expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
|
||||
);
|
||||
} else if (makerAssetProxyIdRight === AssetProxyId.ERC721) {
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
|
||||
'Checking left maker ingress ERC721 account holdings',
|
||||
).to.be.deep.equal(
|
||||
expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
|
||||
);
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
|
||||
'Checking right maker agress ERC721 account holdings',
|
||||
).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]);
|
||||
} else {
|
||||
throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`);
|
||||
}
|
||||
// Paid fees
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress],
|
||||
'Checking left maker egress ERC20 account fees',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress],
|
||||
'Checking right maker egress ERC20 account fees',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[takerAddress][this._feeTokenAddress],
|
||||
'Checking taker egress ERC20 account fees',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]);
|
||||
// Received fees
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
|
||||
'Checking left fee recipient ingress ERC20 account fees',
|
||||
).to.be.bignumber.equal(
|
||||
expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
|
||||
);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
|
||||
'Checking right fee receipient ingress ERC20 account fees',
|
||||
).to.be.bignumber.equal(
|
||||
expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
|
||||
);
|
||||
}
|
||||
} // tslint:disable-line:max-file-line-count
|
||||
|
@ -5,7 +5,7 @@ import { constants } from './constants';
|
||||
import { CancelOrder, MatchOrder } from './types';
|
||||
|
||||
export const orderUtils = {
|
||||
getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||
getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||
const partialAmount = numerator
|
||||
.mul(target)
|
||||
.div(denominator)
|
||||
|
@ -117,21 +117,24 @@ export interface TransferAmountsByMatchOrders {
|
||||
// Left Maker
|
||||
amountBoughtByLeftMaker: BigNumber;
|
||||
amountSoldByLeftMaker: BigNumber;
|
||||
amountReceivedByLeftMaker: BigNumber;
|
||||
feePaidByLeftMaker: BigNumber;
|
||||
// Right Maker
|
||||
amountBoughtByRightMaker: BigNumber;
|
||||
amountSoldByRightMaker: BigNumber;
|
||||
amountReceivedByRightMaker: BigNumber;
|
||||
feePaidByRightMaker: BigNumber;
|
||||
// Taker
|
||||
amountReceivedByTaker: BigNumber;
|
||||
feePaidByTakerLeft: BigNumber;
|
||||
feePaidByTakerRight: BigNumber;
|
||||
totalFeePaidByTaker: BigNumber;
|
||||
// Fee Recipients
|
||||
feeReceivedLeft: BigNumber;
|
||||
feeReceivedRight: BigNumber;
|
||||
}
|
||||
|
||||
export interface TransferAmountsLoggedByMatchOrders {
|
||||
makerAddress: string;
|
||||
takerAddress: string;
|
||||
makerAssetFilledAmount: string;
|
||||
takerAssetFilledAmount: string;
|
||||
makerFeePaid: string;
|
||||
takerFeePaid: string;
|
||||
}
|
||||
|
||||
export interface OrderInfo {
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "1.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535133899,
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1534210131,
|
||||
"version": "1.0.4",
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.4 - _August 13, 2018_
|
||||
## v1.0.6 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.5 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.4 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -21,7 +29,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -47,7 +55,7 @@ CHANGELOG
|
||||
* Pass SolCompilerArtifactAdapter to CoverageSubprovider (#589)
|
||||
* Move callbackErrorReporter over from 0x.js (#579)
|
||||
|
||||
## v0.4.1 - _May 4, 2018_
|
||||
## v0.4.1 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/dev-utils",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -29,7 +29,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/dev-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"chai": "^4.0.1",
|
||||
@ -43,12 +43,12 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/subproviders": "^1.0.5",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"@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",
|
||||
"lodash": "^4.17.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1535133899,
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1534210131,
|
||||
"version": "1.0.4",
|
||||
|
@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.4 - _August 13, 2018_
|
||||
## v1.0.5 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.4 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -21,11 +25,12 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Add `TraceParams` interface for `debug_traceTransaction` parameters (#675)
|
||||
* Add `TransactionReceiptStatus` type (#812)
|
||||
* Add Artifact types: `CompilerSettings`, `CompilerOptions`, `OutputField` (#924)
|
||||
|
||||
## v0.0.2 - _May 31, 2018_
|
||||
## v0.0.2 - _June 1, 2018_
|
||||
|
||||
* Initial publish (#642)
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ethereum-types",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -29,7 +29,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/ethereum-types/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"copyfiles": "^2.0.0",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"shx": "^0.2.2",
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.3",
|
||||
"changes": [
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.3 - _August 13, 2018_
|
||||
## v1.0.1-rc.5 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1-rc.4 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1-rc.3 - _August 14, 2018_
|
||||
|
||||
* Updated to use latest orderFactory interface, fixed `feeRecipient` spelling error in public interface (#936)
|
||||
* Dependencies updated
|
||||
@ -22,7 +30,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-rc.1 - _July 19, 2018_
|
||||
## v1.0.0-rc.1 - _July 20, 2018_
|
||||
|
||||
* Make fill-scenarios compatible with V2 of 0x protocol (#656)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/fill-scenarios",
|
||||
"version": "1.0.1-rc.3",
|
||||
"version": "1.0.1-rc.5",
|
||||
"description": "0x order fill scenario generator",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@ -27,8 +27,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/abi-gen": "^1.0.7",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/lodash": "4.14.104",
|
||||
"copyfiles": "^2.0.0",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
@ -38,13 +38,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.3",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"@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",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.5"
|
||||
},
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.1-rc.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.1",
|
||||
"changes": [
|
||||
@ -6,6 +15,7 @@
|
||||
"note": "Add initial forwarderHelperFactory",
|
||||
"pr": 997
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
}
|
||||
]
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.4 - _August 13, 2018_
|
||||
## v1.0.1-rc.2 - _August 27, 2018_
|
||||
|
||||
* Add inital spec for SRA v2 (#916)
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1-rc.1 - _August 24, 2018_
|
||||
|
||||
* Add initial forwarderHelperFactory (#997)
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/forwarder-helper",
|
||||
"version": "1.0.0-rc.1",
|
||||
"version": "1.0.1-rc.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -15,15 +15,13 @@
|
||||
"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",
|
||||
"run_mocha":
|
||||
"mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --exit",
|
||||
"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"
|
||||
"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"
|
||||
},
|
||||
"config": {
|
||||
"postpublish": {
|
||||
@ -41,17 +39,17 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/forwarder-helper/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.5",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.4",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.3",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@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",
|
||||
"lodash": "^4.17.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/lodash": "^4.14.116",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"chai": "^4.0.1",
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.1-rc.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
@ -6,7 +15,8 @@
|
||||
"note": "Update incorrect relayer api fee recipients response schema",
|
||||
"pr": 974
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.4",
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.4 - _August 13, 2018_
|
||||
## v1.0.1-rc.6 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1-rc.5 - _August 24, 2018_
|
||||
|
||||
* Update incorrect relayer api fee recipients response schema (#974)
|
||||
|
||||
## v1.0.1-rc.4 - _August 14, 2018_
|
||||
|
||||
* Allow for additional properties in txData schema (#938)
|
||||
* Change hexSchema to match `0x` (#937)
|
||||
@ -27,7 +35,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-rc.1 - _July 19, 2018_
|
||||
## v1.0.0-rc.1 - _July 20, 2018_
|
||||
|
||||
* Update schemas for V2 or 0x Protocol (#615)
|
||||
* Added CallData schema (#821)
|
||||
@ -53,7 +61,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.7.23 - _May 4, 2018_
|
||||
## v0.7.23 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/json-schemas",
|
||||
"version": "1.0.1-rc.4",
|
||||
"version": "1.0.1-rc.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -23,7 +23,9 @@
|
||||
"config": {
|
||||
"postpublish": {
|
||||
"assets": [],
|
||||
"docOmitExports": ["schemas"]
|
||||
"docOmitExports": [
|
||||
"schemas"
|
||||
]
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
@ -37,14 +39,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/json-schemas/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@types/node": "^8.0.53",
|
||||
"jsonschema": "^1.2.0",
|
||||
"lodash.values": "^4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@types/lodash.foreach": "^4.5.3",
|
||||
"@types/lodash.values": "^4.3.3",
|
||||
"@types/mocha": "^2.2.42",
|
||||
|
@ -6,7 +6,6 @@ export const relayerApiFeeRecipientsResponseSchema = {
|
||||
{
|
||||
properties: {
|
||||
records: {
|
||||
id: '/relayerApiFeeRecipientsSchema',
|
||||
type: 'array',
|
||||
items: { $ref: '/addressSchema' },
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/metacoin",
|
||||
"version": "0.0.15",
|
||||
"version": "0.0.17",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -29,25 +29,25 @@
|
||||
"author": "",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.5",
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/sol-cov": "^2.0.0",
|
||||
"@0xproject/subproviders": "^1.0.5",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"@0xproject/abi-gen": "^1.0.7",
|
||||
"@0xproject/base-contract": "^2.0.1",
|
||||
"@0xproject/sol-cov": "^2.1.1",
|
||||
"@0xproject/subproviders": "^2.0.1",
|
||||
"@0xproject/tslint-config": "^1.0.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",
|
||||
"@types/mocha": "^5.2.2",
|
||||
"copyfiles": "^2.0.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.5",
|
||||
"run-s": "^0.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/sol-compiler": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/sol-compiler": "^1.1.1",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^2.0.1",
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "1.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535133899,
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1534210131,
|
||||
"version": "1.0.4",
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.4 - _August 13, 2018_
|
||||
## v1.0.6 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.5 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.4 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -21,7 +29,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Added migrations for 0x Protocol v2
|
||||
|
||||
@ -45,7 +53,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.5 - _May 4, 2018_
|
||||
## v0.0.5 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -782,5 +782,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"networks": {}
|
||||
"networks": {
|
||||
"50": {
|
||||
"address": "0xe86bb98fcf9bff3512c74589b78fb168200cc546",
|
||||
"links": {},
|
||||
"constructorArgs": "[\"0x48bacb9266a570d521063ef5dd96e61686dbe788\",\"0xf47261b0000000000000000000000000871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c\"]"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/migrations",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -35,10 +35,10 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/abi-gen": "^1.0.7",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@0xproject/types": "^1.0.1-rc.6",
|
||||
"@types/yargs": "^10.0.0",
|
||||
"copyfiles": "^2.0.0",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
@ -49,15 +49,15 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.3",
|
||||
"@0xproject/sol-compiler": "^1.0.5",
|
||||
"@0xproject/subproviders": "^1.0.5",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"@0xproject/base-contract": "^2.0.1",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.6",
|
||||
"@0xproject/sol-compiler": "^1.1.1",
|
||||
"@0xproject/subproviders": "^2.0.1",
|
||||
"@0xproject/typescript-typings": "^1.0.5",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@0xproject/web3-wrapper": "^2.0.1",
|
||||
"@ledgerhq/hw-app-eth": "^4.3.0",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.5"
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@0xproject/monorepo-scripts",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.7",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
|
@ -18,7 +18,6 @@ import { DocGenerateAndUploadUtils } from './utils/doc_generate_and_upload_utils
|
||||
import { publishReleaseNotesAsync } from './utils/github_release_utils';
|
||||
import { utils } from './utils/utils';
|
||||
|
||||
const DOC_GEN_COMMAND = 'docs:json';
|
||||
const NPM_NAMESPACE = '@0xproject/';
|
||||
const TODAYS_TIMESTAMP = moment().unix();
|
||||
|
||||
@ -75,9 +74,11 @@ async function confirmAsync(message: string): Promise<void> {
|
||||
});
|
||||
utils.log(`Calling 'lerna publish'...`);
|
||||
await lernaPublishAsync(packageToNextVersion);
|
||||
if (!configs.IS_LOCAL_PUBLISH) {
|
||||
const isStaging = false;
|
||||
const shouldUploadDocs = !configs.IS_LOCAL_PUBLISH;
|
||||
const shouldUploadDocs = true;
|
||||
await generateAndUploadDocJsonsAsync(packagesWithDocs, isStaging, shouldUploadDocs);
|
||||
}
|
||||
const isDryRun = configs.IS_LOCAL_PUBLISH;
|
||||
await publishReleaseNotesAsync(updatedPublicPackages, isDryRun);
|
||||
})().catch(err => {
|
||||
@ -88,7 +89,7 @@ async function confirmAsync(message: string): Promise<void> {
|
||||
function getPackagesWithDocs(allUpdatedPackages: Package[]): Package[] {
|
||||
const rootPackageJsonPath = `${constants.monorepoRootPath}/package.json`;
|
||||
const rootPackageJson = JSON.parse(fs.readFileSync(rootPackageJsonPath).toString());
|
||||
const packagesWithDocPagesStringIfExist = _.get(rootPackageJson, 'configs.packagesWithDocPages', undefined);
|
||||
const packagesWithDocPagesStringIfExist = _.get(rootPackageJson, 'config.packagesWithDocPages', undefined);
|
||||
if (_.isUndefined(packagesWithDocPagesStringIfExist)) {
|
||||
return []; // None to generate & publish
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ const args = yargs
|
||||
const allUpdatedPackages = await utils.getUpdatedPackagesAsync(shouldIncludePrivate);
|
||||
|
||||
await publishReleaseNotesAsync(allUpdatedPackages, isDryRun);
|
||||
process.exit(0);
|
||||
})().catch(err => {
|
||||
utils.log(err);
|
||||
process.exit(1);
|
||||
|
@ -85,11 +85,13 @@ function logIfDefined(x: any): void {
|
||||
logIfDefined(packageError.error.stdout);
|
||||
logIfDefined(packageError.error.stack);
|
||||
});
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
})().catch(err => {
|
||||
utils.log(`Unexpected error: ${err.message}`);
|
||||
process.exit(0);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
async function testInstallPackageAsync(
|
||||
@ -144,7 +146,7 @@ async function testInstallPackageAsync(
|
||||
const transpiledIndexFilePath = path.join(testDirectory, 'index.js');
|
||||
utils.log(`Running test script with ${packageName} imported`);
|
||||
await execAsync(`node ${transpiledIndexFilePath}`);
|
||||
utils.log(`Successfilly ran test script with ${packageName} imported`);
|
||||
utils.log(`Successfully ran test script with ${packageName} imported`);
|
||||
}
|
||||
await rimrafAsync(testDirectory);
|
||||
}
|
||||
|
@ -19,11 +19,6 @@ CHANGELOG
|
||||
|
||||
export const changelogUtils = {
|
||||
getChangelogMdTitle(versionChangelog: VersionChangelog): string {
|
||||
if (_.isUndefined(versionChangelog.timestamp)) {
|
||||
throw new Error(
|
||||
'All CHANGELOG.json entries must be updated to include a timestamp before generating their MD version',
|
||||
);
|
||||
}
|
||||
const date = moment(`${versionChangelog.timestamp}`, 'X').format('MMMM D, YYYY');
|
||||
const title = `\n## v${versionChangelog.version} - _${date}_\n\n`;
|
||||
return title;
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.1-rc.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix missing `BlockParamLiteral` type import issue"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Remove Caller and Trezor SignatureTypes",
|
||||
"pr": 1015
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.4",
|
||||
"changes": [
|
||||
@ -39,7 +57,8 @@
|
||||
"Update `findFeeOrdersThatCoverFeesForTargetOrders` to round the the nearest integer when calculating required fees",
|
||||
"pr": 997
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.3",
|
||||
|
@ -5,7 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.3 - _August 13, 2018_
|
||||
## v1.0.1-rc.6 - _August 27, 2018_
|
||||
|
||||
* Fix missing `BlockParamLiteral` type import issue
|
||||
|
||||
## v1.0.1-rc.5 - _Invalid date_
|
||||
|
||||
* Remove Caller and Trezor SignatureTypes (#1015)
|
||||
|
||||
## v1.0.1-rc.4 - _August 24, 2018_
|
||||
|
||||
* Remove rounding error being thrown when maker amount is very small (#959)
|
||||
* Added rateUtils and sortingUtils (#953)
|
||||
* Update marketUtils api such that all optional parameters are bundled into one optional param and more defaults are provided (#954)
|
||||
* Instead of exporting signature util methods individually, they are now exported as `signatureUtils` (#924)
|
||||
* Export types: `SignedOrder`, `Order`, `OrderRelevantState`, `OrderState`, `ECSignature`, `ERC20AssetData`, `ERC721AssetData`, `AssetProxyId`, `SignerType`, `SignatureType`, `OrderStateValid`, `OrderStateInvalid`, `ExchangeContractErrs`, `TradeSide`, `TransferType`, `FindFeeOrdersThatCoverFeesForTargetOrdersOpts`, `FindOrdersThatCoverMakerAssetFillAmountOpts`, `FeeOrdersAndRemainingFeeAmount`, `OrdersAndRemainingFillAmount`, `Provider`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload` (#924)
|
||||
* Rename `resultOrders` to `resultFeeOrders` for object returned by `findFeeOrdersThatCoverFeesForTargetOrders` in `marketUtils` api (#997)
|
||||
* Make `sortFeeOrdersByFeeAdjustedRate` in `sortingUtils` generic (#997)
|
||||
* Update `findFeeOrdersThatCoverFeesForTargetOrders` to round the the nearest integer when calculating required fees (#997)
|
||||
|
||||
## v1.0.1-rc.3 - _August 14, 2018_
|
||||
|
||||
* Update ecSignOrderHashAsync to return signature string with signature type byte. Removes messagePrefixOpts. (#914)
|
||||
* Added a synchronous `createOrder` method in `orderFactory`, updated public interfaces to support some optional parameters (#936)
|
||||
@ -28,7 +47,7 @@ CHANGELOG
|
||||
|
||||
* Upgrade ethereumjs-abi dep including a fix so that addresses starting with 0 are properly decoded by `decodeERC20AssetData`
|
||||
|
||||
## v1.0.0-rc.1 - _July 19, 2018_
|
||||
## v1.0.0-rc.1 - _July 20, 2018_
|
||||
|
||||
* Refactor to work with V2 of 0x protocol (#636)
|
||||
* Export parseECSignature method (#684)
|
||||
@ -54,7 +73,7 @@ CHANGELOG
|
||||
|
||||
* Add orderStateUtils, a module for computing order state needed to decide if an order is still valid
|
||||
|
||||
## v0.0.4 - _May 4, 2018_
|
||||
## v0.0.4 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/order-utils",
|
||||
"version": "1.0.1-rc.3",
|
||||
"version": "1.0.1-rc.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -40,8 +40,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"chai": "^4.0.1",
|
||||
@ -59,16 +59,16 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.5",
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.4",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"@0xproject/assert": "^1.0.7",
|
||||
"@0xproject/base-contract": "^2.0.1",
|
||||
"@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/web3-wrapper": "^2.0.1",
|
||||
"@types/node": "^8.0.53",
|
||||
"bn.js": "^4.11.8",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethereumjs-abi": "0.6.5",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "3.0.22",
|
||||
|
@ -81,7 +81,7 @@ export class OrderStateUtils {
|
||||
const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus(
|
||||
sidedOrderRelevantState.filledTakerAssetAmount,
|
||||
);
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(
|
||||
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(
|
||||
remainingTakerAssetAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
@ -191,7 +191,7 @@ export class OrderStateUtils {
|
||||
);
|
||||
const remainingFillableTakerAssetAmountGivenMakersStatus = signedOrder.makerAssetAmount.eq(0)
|
||||
? new BigNumber(0)
|
||||
: utils.getPartialAmount(
|
||||
: utils.getPartialAmountFloor(
|
||||
orderRelevantMakerState.remainingFillableAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
|
@ -24,7 +24,7 @@ export class OrderValidationUtils {
|
||||
* @param denominator Denominator value. When used to check an order, pass in `order.takerAssetAmount`
|
||||
* @param target Target value. When used to check an order, pass in `order.makerAssetAmount`
|
||||
*/
|
||||
public static isRoundingError(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
|
||||
public static isRoundingErrorFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
|
||||
// Solidity's mulmod() in JS
|
||||
// Source: https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions
|
||||
if (denominator.eq(0)) {
|
||||
@ -58,7 +58,7 @@ export class OrderValidationUtils {
|
||||
zrxAssetData: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const fillMakerTokenAmount = utils.getPartialAmount(
|
||||
const fillMakerTokenAmount = utils.getPartialAmountFloor(
|
||||
fillTakerAssetAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
@ -79,7 +79,7 @@ export class OrderValidationUtils {
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const makerFeeAmount = utils.getPartialAmount(
|
||||
const makerFeeAmount = utils.getPartialAmountFloor(
|
||||
fillTakerAssetAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerFee,
|
||||
@ -92,7 +92,7 @@ export class OrderValidationUtils {
|
||||
TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
const takerFeeAmount = utils.getPartialAmount(
|
||||
const takerFeeAmount = utils.getPartialAmountFloor(
|
||||
fillTakerAssetAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.takerFee,
|
||||
@ -218,7 +218,7 @@ export class OrderValidationUtils {
|
||||
zrxAssetData,
|
||||
);
|
||||
|
||||
const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingError(
|
||||
const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingErrorFloor(
|
||||
desiredFillTakerTokenAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
|
@ -53,11 +53,6 @@ export const signatureUtils = {
|
||||
return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
|
||||
}
|
||||
|
||||
case SignatureType.Caller:
|
||||
// HACK: We currently do not "validate" the caller signature type.
|
||||
// It can only be validated during Exchange contract execution.
|
||||
throw new Error('Caller signature type cannot be validated off-chain');
|
||||
|
||||
case SignatureType.Wallet: {
|
||||
const isValid = await signatureUtils.isValidWalletSignatureAsync(
|
||||
provider,
|
||||
@ -82,12 +77,6 @@ export const signatureUtils = {
|
||||
return signatureUtils.isValidPresignedSignatureAsync(provider, data, signerAddress);
|
||||
}
|
||||
|
||||
case SignatureType.Trezor: {
|
||||
const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, SignerType.Trezor);
|
||||
const ecSignature = signatureUtils.parseECSignature(signature);
|
||||
return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`);
|
||||
}
|
||||
@ -293,10 +282,6 @@ export const signatureUtils = {
|
||||
signatureType = SignatureType.EthSign;
|
||||
break;
|
||||
}
|
||||
case SignerType.Trezor: {
|
||||
signatureType = SignatureType.Trezor;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unrecognized SignerType: ${signerType}`);
|
||||
}
|
||||
@ -306,7 +291,7 @@ export const signatureUtils = {
|
||||
/**
|
||||
* Combines the signature proof and the Signature Type.
|
||||
* @param signature The hex encoded signature proof
|
||||
* @param signatureType The signature type, i.e EthSign, Trezor, Wallet etc.
|
||||
* @param signatureType The signature type, i.e EthSign, Wallet etc.
|
||||
* @return Hex encoded string of signature proof with Signature Type
|
||||
*/
|
||||
convertToSignatureWithType(signature: string, signatureType: SignatureType): string {
|
||||
@ -333,12 +318,6 @@ export const signatureUtils = {
|
||||
const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
|
||||
return prefixedMsgHex;
|
||||
}
|
||||
case SignerType.Trezor: {
|
||||
const msgBuff = ethUtil.toBuffer(message);
|
||||
const prefixedMsgBuff = hashTrezorPersonalMessage(msgBuff);
|
||||
const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
|
||||
return prefixedMsgHex;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unrecognized SignerType: ${signerType}`);
|
||||
}
|
||||
@ -350,7 +329,7 @@ export const signatureUtils = {
|
||||
*/
|
||||
parseECSignature(signature: string): ECSignature {
|
||||
assert.isHexString('signature', signature);
|
||||
const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor];
|
||||
const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712];
|
||||
assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes);
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
@ -361,11 +340,6 @@ export const signatureUtils = {
|
||||
},
|
||||
};
|
||||
|
||||
function hashTrezorPersonalMessage(message: Buffer): Buffer {
|
||||
const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.byteLength));
|
||||
return ethUtil.sha3(Buffer.concat([prefix, message]));
|
||||
}
|
||||
|
||||
function parseValidatorSignature(signature: string): ValidatorSignature {
|
||||
assert.isOneOfExpectedSignatureTypes(signature, [SignatureType.Validator]);
|
||||
// tslint:disable:custom-no-magic-numbers
|
||||
|
@ -12,7 +12,7 @@ export const utils = {
|
||||
const milisecondsInSecond = 1000;
|
||||
return new BigNumber(Date.now() / milisecondsInSecond).round();
|
||||
},
|
||||
getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||
getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||
const fillMakerTokenAmount = numerator
|
||||
.mul(target)
|
||||
.div(denominator)
|
||||
|
@ -16,7 +16,7 @@ describe('OrderValidationUtils', () => {
|
||||
const denominator = new BigNumber(999);
|
||||
const target = new BigNumber(50);
|
||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
|
||||
@ -25,7 +25,7 @@ describe('OrderValidationUtils', () => {
|
||||
const denominator = new BigNumber(9991);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
|
||||
@ -34,7 +34,7 @@ describe('OrderValidationUtils', () => {
|
||||
const denominator = new BigNumber(9989);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
|
||||
@ -43,7 +43,7 @@ describe('OrderValidationUtils', () => {
|
||||
const denominator = new BigNumber(7);
|
||||
const target = new BigNumber(10);
|
||||
// rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
|
||||
@ -52,7 +52,7 @@ describe('OrderValidationUtils', () => {
|
||||
const denominator = new BigNumber(2);
|
||||
const target = new BigNumber(10);
|
||||
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
|
||||
@ -63,7 +63,7 @@ describe('OrderValidationUtils', () => {
|
||||
const target = new BigNumber(105762562);
|
||||
// rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) /
|
||||
// (76564*105762562/676373677) = 0.0007%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
});
|
||||
|
@ -76,20 +76,6 @@ describe('Signature utils', () => {
|
||||
);
|
||||
expect(isValidSignatureLocal).to.be.true();
|
||||
});
|
||||
|
||||
it('should return true for a valid Trezor signature', async () => {
|
||||
dataHex = '0xd0d994e31c88f33fd8a572552a70ed339de579e5ba49ee1d17cc978bbe1cdd21';
|
||||
address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
|
||||
const trezorSignature =
|
||||
'0x1ce4760660e6495b5ae6723087bea073b3a99ce98ea81fdf00c240279c010e63d05b87bc34c4d67d4776e8d5aeb023a67484f4eaf0fd353b40893e5101e845cd9908';
|
||||
const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync(
|
||||
provider,
|
||||
dataHex,
|
||||
trezorSignature,
|
||||
address,
|
||||
);
|
||||
expect(isValidSignatureLocal).to.be.true();
|
||||
});
|
||||
});
|
||||
describe('#isValidECSignature', () => {
|
||||
const signature = {
|
||||
@ -270,15 +256,6 @@ describe('Signature utils', () => {
|
||||
r: '0xaca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d64393',
|
||||
s: '0x46b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf2',
|
||||
};
|
||||
it('should concatenate v,r,s and append the Trezor signature type', async () => {
|
||||
const expectedSignatureWithSignatureType =
|
||||
'0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf208';
|
||||
const signatureWithSignatureType = signatureUtils.convertECSignatureToSignatureHex(
|
||||
ecSignature,
|
||||
SignerType.Trezor,
|
||||
);
|
||||
expect(signatureWithSignatureType).to.equal(expectedSignatureWithSignatureType);
|
||||
});
|
||||
it('should concatenate v,r,s and append the EthSign signature type when SignerType is Default', async () => {
|
||||
const expectedSignatureWithSignatureType =
|
||||
'0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf203';
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix missing `BlockParamLiteral` type import issue"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.4",
|
||||
"changes": [
|
||||
@ -11,7 +20,8 @@
|
||||
"note": "Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order`",
|
||||
"pr": 924
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.3",
|
||||
|
@ -5,7 +5,16 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1-rc.3 - _August 13, 2018_
|
||||
## v1.0.1-rc.5 - _August 27, 2018_
|
||||
|
||||
* Fix missing `BlockParamLiteral` type import issue
|
||||
|
||||
## v1.0.1-rc.4 - _August 24, 2018_
|
||||
|
||||
* Export types: `ExchangeContractErrs`, `OrderRelevantState`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload` (#924)
|
||||
* Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order` (#924)
|
||||
|
||||
## v1.0.1-rc.3 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -21,7 +30,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-rc.1 - _July 19, 2018_
|
||||
## v1.0.0-rc.1 - _July 20, 2018_
|
||||
|
||||
* Add support for ERC721 event watching and Exchange V2 events (#887)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/order-watcher",
|
||||
"version": "1.0.1-rc.3",
|
||||
"version": "1.0.1-rc.5",
|
||||
"description": "An order watcher daemon that watches for order validity",
|
||||
"keywords": [
|
||||
"0x",
|
||||
@ -43,10 +43,10 @@
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/migrations": "^1.0.4",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/abi-gen": "^1.0.7",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/migrations": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/bintrees": "^1.0.2",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
@ -71,18 +71,18 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^1.0.5",
|
||||
"@0xproject/base-contract": "^2.0.0-rc.1",
|
||||
"@0xproject/contract-wrappers": "^1.0.1-rc.3",
|
||||
"@0xproject/fill-scenarios": "^1.0.1-rc.3",
|
||||
"@0xproject/json-schemas": "^1.0.1-rc.4",
|
||||
"@0xproject/order-utils": "^1.0.1-rc.3",
|
||||
"@0xproject/types": "^1.0.1-rc.4",
|
||||
"@0xproject/typescript-typings": "^1.0.4",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/web3-wrapper": "^1.2.0",
|
||||
"@0xproject/assert": "^1.0.7",
|
||||
"@0xproject/base-contract": "^2.0.1",
|
||||
"@0xproject/contract-wrappers": "^1.0.1-rc.5",
|
||||
"@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",
|
||||
"bintrees": "^1.0.2",
|
||||
"ethereum-types": "^1.0.4",
|
||||
"ethereum-types": "^1.0.5",
|
||||
"ethereumjs-blockstream": "5.0.0",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.5"
|
||||
|
@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1535377027,
|
||||
"version": "1.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1535133899,
|
||||
"version": "1.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1534210131,
|
||||
"version": "1.0.5",
|
||||
|
@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.5 - _August 13, 2018_
|
||||
## v1.0.7 - _August 27, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.6 - _August 24, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.5 - _August 14, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -25,7 +33,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _July 19, 2018_
|
||||
## v1.0.0 - _July 20, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@ -45,7 +53,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.13 - _May 31, 2018_
|
||||
## v0.0.13 - _June 1, 2018_
|
||||
|
||||
* Incorrect publish that was unpublished
|
||||
|
||||
@ -53,7 +61,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.11 - _May 4, 2018_
|
||||
## v0.0.11 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/react-docs",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.7",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -24,8 +24,8 @@
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/dev-utils": "^1.0.4",
|
||||
"@0xproject/tslint-config": "^1.0.5",
|
||||
"@0xproject/dev-utils": "^1.0.6",
|
||||
"@0xproject/tslint-config": "^1.0.6",
|
||||
"@types/compare-versions": "^3.0.0",
|
||||
"copyfiles": "^2.0.0",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
@ -34,8 +34,8 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/react-shared": "^1.0.6",
|
||||
"@0xproject/utils": "^1.0.5",
|
||||
"@0xproject/react-shared": "^1.0.8",
|
||||
"@0xproject/utils": "^1.0.7",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/material-ui": "0.18.0",
|
||||
"@types/node": "^8.0.53",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user