Merge development

This commit is contained in:
Fabio Berger 2018-08-14 14:21:47 -07:00
commit 2f2582a0da
248 changed files with 5998 additions and 2024 deletions

View File

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

View File

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

View File

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

View File

@ -14,6 +14,8 @@
"report_coverage": "lcov-result-merger 'packages/*/coverage/lcov.info' | coveralls", "report_coverage": "lcov-result-merger 'packages/*/coverage/lcov.info' | coveralls",
"test:installation": "node ./packages/monorepo-scripts/lib/test_installation.js", "test:installation": "node ./packages/monorepo-scripts/lib/test_installation.js",
"test:installation:local": "IS_LOCAL_PUBLISH=true node ./packages/monorepo-scripts/lib/test_installation.js", "test:installation:local": "IS_LOCAL_PUBLISH=true node ./packages/monorepo-scripts/lib/test_installation.js",
"test:publish:circleci:comment": "HACK(albrow) We need an automated way to login to npm and echo+sleep piped to stdin was the only way I could find to do it.",
"test:publish:circleci": "{ echo \"test\"; sleep 1; echo \"test\"; sleep 1; echo \"test@example.com\"; } | npm login --registry=http://localhost:4873 && IS_LOCAL_PUBLISH=true run-s script:publish test:installation:local",
"run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild:no_website script:publish", "run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild:no_website script:publish",
"run:publish:local": "IS_LOCAL_PUBLISH=true yarn run:publish", "run:publish:local": "IS_LOCAL_PUBLISH=true yarn run:publish",
"script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js", "script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js",

View File

@ -1,4 +1,17 @@
[ [
{
"version": "1.0.1-rc.3",
"changes": [
{
"note": "Dependencies updated"
},
{
"pr": 914,
"note": "Update ecSignOrderHashAsync to return the signature as a string for immediate use in contracts"
}
],
"timestamp": 1534210131
},
{ {
"version": "1.0.1-rc.2", "version": "1.0.1-rc.2",
"changes": [ "changes": [

View File

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

View File

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

View File

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

View File

@ -48,8 +48,6 @@ export {
OrderInfo, OrderInfo,
} from '@0xproject/contract-wrappers'; } from '@0xproject/contract-wrappers';
export { MessagePrefixType, MessagePrefixOpts } from '@0xproject/order-utils';
export { export {
ExchangeContractErrs, ExchangeContractErrs,
Order, Order,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
[ [
{ {
"version": "1.0.1-rc.3", "version": "1.0.1-rc.4",
"changes": [ "changes": [
{ {
"note": "Export missing ExchangeSignatureValidatorApprovalEventArgs type", "note": "Export missing ExchangeSignatureValidatorApprovalEventArgs type",
@ -8,6 +8,24 @@
} }
] ]
}, },
{
"version": "1.0.1-rc.3",
"changes": [
{
"pr": 915,
"note": "Added strict encoding/decoding checks for sendTransaction and call"
},
{
"note": "Add ForwarderWrapper",
"pr": 934
},
{
"note": "Optimize orders in ForwarderWrapper",
"pr": 936
}
],
"timestamp": 1534210131
},
{ {
"version": "1.0.1-rc.2", "version": "1.0.1-rc.2",
"changes": [ "changes": [

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
{ {
"private": true, "private": true,
"name": "contracts", "name": "contracts",
"version": "2.1.39", "version": "2.1.40",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@ -46,11 +46,11 @@
}, },
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md", "homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
"devDependencies": { "devDependencies": {
"@0xproject/abi-gen": "^1.0.4", "@0xproject/abi-gen": "^1.0.5",
"@0xproject/dev-utils": "^1.0.3", "@0xproject/dev-utils": "^1.0.4",
"@0xproject/sol-cov": "^1.0.3", "@0xproject/sol-cov": "^2.0.0",
"@0xproject/subproviders": "^1.0.4", "@0xproject/subproviders": "^1.0.5",
"@0xproject/tslint-config": "^1.0.4", "@0xproject/tslint-config": "^1.0.5",
"@types/bn.js": "^4.11.0", "@types/bn.js": "^4.11.0",
"@types/ethereumjs-abi": "^0.6.0", "@types/ethereumjs-abi": "^0.6.0",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
@ -62,30 +62,30 @@
"copyfiles": "^1.2.0", "copyfiles": "^1.2.0",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"make-promises-safe": "^1.1.0", "make-promises-safe": "^1.1.0",
"mocha": "^4.0.1", "mocha": "^4.1.0",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",
"shx": "^0.2.2", "shx": "^0.2.2",
"solc": "^0.4.24", "solc": "^0.4.24",
"solhint": "^1.2.1", "solhint": "^1.2.1",
"tslint": "5.11.0", "tslint": "5.11.0",
"typescript": "2.7.1", "typescript": "2.9.2",
"yargs": "^10.0.3" "yargs": "^10.0.3"
}, },
"dependencies": { "dependencies": {
"@0xproject/base-contract": "^1.0.4", "@0xproject/base-contract": "^2.0.0-rc.1",
"@0xproject/order-utils": "^1.0.1-rc.2", "@0xproject/order-utils": "^1.0.1-rc.3",
"@0xproject/sol-compiler": "^1.0.4", "@0xproject/sol-compiler": "^1.0.5",
"@0xproject/types": "^1.0.1-rc.3", "@0xproject/types": "^1.0.1-rc.4",
"@0xproject/typescript-typings": "^1.0.3", "@0xproject/typescript-typings": "^1.0.4",
"@0xproject/utils": "^1.0.4", "@0xproject/utils": "^1.0.5",
"@0xproject/web3-wrapper": "^1.1.2", "@0xproject/web3-wrapper": "^1.2.0",
"@types/js-combinatorics": "^0.5.29", "@types/js-combinatorics": "^0.5.29",
"bn.js": "^4.11.8", "bn.js": "^4.11.8",
"ethereum-types": "^1.0.3", "ethereum-types": "^1.0.4",
"ethereumjs-abi": "0.6.5", "ethereumjs-abi": "0.6.5",
"ethereumjs-util": "^5.1.1", "ethereumjs-util": "^5.1.1",
"ethers": "3.0.22", "ethers": "3.0.22",
"js-combinatorics": "^0.5.3", "js-combinatorics": "^0.5.3",
"lodash": "^4.17.4" "lodash": "^4.17.5"
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,7 +28,7 @@ contract MAssets is
/// @dev Transfers given amount of asset to sender. /// @dev Transfers given amount of asset to sender.
/// @param assetData Byte array encoded for the respective asset proxy. /// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender. /// @param amount Amount of asset to transfer to sender.
function transferPurchasedAssetToSender( function transferAssetToSender(
bytes memory assetData, bytes memory assetData,
uint256 amount uint256 amount
) )

View File

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

View File

@ -1,42 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/libs/LibOrder.sol";
import "../../protocol/Exchange/libs/LibFillResults.sol";
import "../interfaces/IForwarderCore.sol";
contract MForwarderCore is
IForwarderCore
{
/// @dev Ensures that all ZRX fees have been repurchased and no extra WETH owned by this contract has been sold.
/// @param orderFillResults Amounts filled and fees paid for primary orders.
/// @param feeOrderFillResults Amounts filled and fees paid for fee orders.
/// @param zrxBuyAmount The amount of ZRX that needed to be repurchased after filling primary orders.
function assertValidFillResults(
LibFillResults.FillResults memory orderFillResults,
LibFillResults.FillResults memory feeOrderFillResults,
uint256 zrxBuyAmount
)
internal
view;
}

View File

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

View File

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

View File

@ -24,20 +24,17 @@ import "./LibOrder.sol";
contract LibAbiEncoder { contract LibAbiEncoder {
/// @dev ABI encodes calldata for `fillOrder` in memory and returns the address range. /// @dev ABI encodes calldata for `fillOrder`.
/// This range can be passed into `call` or `delegatecall` to invoke an external
/// call to `fillOrder`.
/// @param order Order struct containing order specifications. /// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker. /// @param signature Proof that order has been created by maker.
/// @return calldataBegin Memory address of ABI encoded calldata. /// @return ABI encoded calldata for `fillOrder`.
/// @return calldataLength Lenfgth of ABI encoded calldata.
function abiEncodeFillOrder( function abiEncodeFillOrder(
LibOrder.Order memory order, LibOrder.Order memory order,
uint256 takerAssetFillAmount, uint256 takerAssetFillAmount,
bytes memory signature bytes memory signature
) )
public internal
pure pure
returns (bytes memory fillOrderCalldata) returns (bytes memory fillOrderCalldata)
{ {
@ -207,10 +204,10 @@ contract LibAbiEncoder {
} }
// Set length of calldata // Set length of calldata
mstore( mstore(fillOrderCalldata, sub(dataAreaEnd, add(fillOrderCalldata, 0x20)))
fillOrderCalldata,
sub(dataAreaEnd, add(fillOrderCalldata, 0x20)) // Increment free memory pointer
) mstore(0x40, dataAreaEnd)
} }
return fillOrderCalldata; return fillOrderCalldata;

View File

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

View File

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

View File

@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/Exchange.sol"; import "../../protocol/Exchange/Exchange.sol";
// solhint-disable no-empty-blocks
contract TestExchangeInternals is contract TestExchangeInternals is
Exchange Exchange
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@ import * as _ from 'lodash';
import 'make-promises-safe'; import 'make-promises-safe';
import { ExchangeContract, ExchangeFillEventArgs } from '../../generated_contract_wrappers/exchange'; import { ExchangeContract, ExchangeFillEventArgs } from '../../generated_contract_wrappers/exchange';
import { TestLibsContract } from '../../generated_contract_wrappers/test_libs';
import { artifacts } from './artifacts'; import { artifacts } from './artifacts';
import { expectTransactionFailedAsync } from './assertions'; import { expectTransactionFailedAsync } from './assertions';
@ -123,6 +124,8 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
exchangeContract.address, exchangeContract.address,
); );
const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults);
const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils( const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils(
orderFactory, orderFactory,
ownerAddress, ownerAddress,
@ -132,6 +135,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
zrxAssetData, zrxAssetData,
exchangeWrapper, exchangeWrapper,
assetWrapper, assetWrapper,
testLibsContract,
); );
return fillOrderCombinatorialUtils; return fillOrderCombinatorialUtils;
} }
@ -145,6 +149,7 @@ export class FillOrderCombinatorialUtils {
public zrxAssetData: string; public zrxAssetData: string;
public exchangeWrapper: ExchangeWrapper; public exchangeWrapper: ExchangeWrapper;
public assetWrapper: AssetWrapper; public assetWrapper: AssetWrapper;
public testLibsContract: TestLibsContract;
public static generateFillOrderCombinations(): FillScenario[] { public static generateFillOrderCombinations(): FillScenario[] {
const takerScenarios = [ const takerScenarios = [
TakerScenario.Unspecified, TakerScenario.Unspecified,
@ -329,6 +334,7 @@ export class FillOrderCombinatorialUtils {
zrxAssetData: string, zrxAssetData: string,
exchangeWrapper: ExchangeWrapper, exchangeWrapper: ExchangeWrapper,
assetWrapper: AssetWrapper, assetWrapper: AssetWrapper,
testLibsContract: TestLibsContract,
) { ) {
this.orderFactory = orderFactory; this.orderFactory = orderFactory;
this.ownerAddress = ownerAddress; this.ownerAddress = ownerAddress;
@ -338,6 +344,7 @@ export class FillOrderCombinatorialUtils {
this.zrxAssetData = zrxAssetData; this.zrxAssetData = zrxAssetData;
this.exchangeWrapper = exchangeWrapper; this.exchangeWrapper = exchangeWrapper;
this.assetWrapper = assetWrapper; this.assetWrapper = assetWrapper;
this.testLibsContract = testLibsContract;
} }
public async testFillOrderScenarioAsync( public async testFillOrderScenarioAsync(
provider: Provider, provider: Provider,
@ -410,6 +417,8 @@ export class FillOrderCombinatorialUtils {
lazyStore, lazyStore,
fillRevertReasonIfExists, fillRevertReasonIfExists,
); );
await this._abiEncodeFillOrderAndAssertOutcomeAsync(signedOrder, takerAssetFillAmount);
} }
private async _fillOrderAndAssertOutcomeAsync( private async _fillOrderAndAssertOutcomeAsync(
signedOrder: SignedOrder, signedOrder: SignedOrder,
@ -456,6 +465,29 @@ export class FillOrderCombinatorialUtils {
signedOrder.takerAssetAmount, signedOrder.takerAssetAmount,
signedOrder.makerAssetAmount, signedOrder.makerAssetAmount,
); );
const expMakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.makerFee,
);
const expTakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.takerFee,
);
const fillResults = await this.exchangeWrapper.getFillOrderResultsAsync(signedOrder, this.takerAddress, {
takerAssetFillAmount,
});
expect(fillResults.takerAssetFilledAmount).to.be.bignumber.equal(
expFilledTakerAmount,
'takerAssetFilledAmount',
);
expect(fillResults.makerAssetFilledAmount).to.be.bignumber.equal(
expFilledMakerAmount,
'makerAssetFilledAmount',
);
expect(fillResults.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'takerFeePaid');
expect(fillResults.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'makerFeePaid');
// - Let's fill the order! // - Let's fill the order!
const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, {
@ -479,17 +511,7 @@ export class FillOrderCombinatorialUtils {
expFilledTakerAmount, expFilledTakerAmount,
'log.args.takerAssetFilledAmount', 'log.args.takerAssetFilledAmount',
); );
const expMakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.makerFee,
);
expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid'); expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid');
const expTakerFeePaid = orderUtils.getPartialAmount(
expFilledTakerAmount,
signedOrder.takerAssetAmount,
signedOrder.takerFee,
);
expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid'); expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid');
expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash'); expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash');
expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData'); expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData');
@ -571,6 +593,19 @@ export class FillOrderCombinatorialUtils {
'ZRXAssetBalanceOfFeeRecipient', 'ZRXAssetBalanceOfFeeRecipient',
); );
} }
private async _abiEncodeFillOrderAndAssertOutcomeAsync(
signedOrder: SignedOrder,
takerAssetFillAmount: BigNumber,
): Promise<void> {
const params = orderUtils.createFill(signedOrder, takerAssetFillAmount);
const expectedAbiEncodedData = this.exchangeWrapper.abiEncodeFillOrder(signedOrder, { takerAssetFillAmount });
const libsAbiEncodedData = await this.testLibsContract.publicAbiEncodeFillOrder.callAsync(
params.order,
params.takerAssetFillAmount,
params.signature,
);
expect(libsAbiEncodedData).to.be.equal(expectedAbiEncodedData, 'ABIEncodedFillOrderData');
}
private async _getTakerAssetFillAmountAsync( private async _getTakerAssetFillAmountAsync(
signedOrder: SignedOrder, signedOrder: SignedOrder,
takerAssetFillAmountScenario: TakerAssetFillAmountScenario, takerAssetFillAmountScenario: TakerAssetFillAmountScenario,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
export const ordersSchema = { export const ordersSchema = {
id: '/ordersSchema', id: '/ordersSchema',
type: 'array', type: 'array',
items: { $ref: '/Order' }, items: { $ref: '/orderSchema' },
}; };

View File

@ -0,0 +1,10 @@
export const paginatedCollectionSchema = {
id: '/paginatedCollectionSchema',
type: 'object',
properties: {
total: { type: 'number' },
perPage: { type: 'number' },
page: { type: 'number' },
},
required: ['total', 'perPage', 'page'],
};

View File

@ -0,0 +1,38 @@
export const relayerApiAssetDataPairsResponseSchema = {
id: '/relayerApiAssetDataPairsResponseSchema',
type: 'object',
allOf: [
{ $ref: '/paginatedCollectionSchema' },
{
properties: {
records: { $ref: '/relayerApiAssetDataPairsSchema' },
},
required: ['records'],
},
],
};
export const relayerApiAssetDataPairsSchema = {
id: '/relayerApiAssetDataPairsSchema',
type: 'array',
items: {
properties: {
assetDataA: { $ref: '/relayerApiAssetDataTradeInfoSchema' },
assetDataB: { $ref: '/relayerApiAssetDataTradeInfoSchema' },
},
required: ['assetDataA', 'assetDataB'],
type: 'object',
},
};
export const relayerApiAssetDataTradeInfoSchema = {
id: '/relayerApiAssetDataTradeInfoSchema',
type: 'object',
properties: {
assetData: { $ref: '/hexSchema' },
minAmount: { $ref: '/numberSchema' },
maxAmount: { $ref: '/numberSchema' },
precision: { type: 'number' },
},
required: ['assetData'],
};

View File

@ -1,8 +1,8 @@
export const relayerApiErrorResponseSchema = { export const relayerApiErrorResponseSchema = {
id: '/RelayerApiErrorResponse', id: '/relayerApiErrorResponseSchema',
type: 'object', type: 'object',
properties: { properties: {
code: { type: 'number' }, code: { type: 'integer', minimum: 100, maximum: 103 },
reason: { type: 'string' }, reason: { type: 'string' },
validationErrors: { validationErrors: {
type: 'array', type: 'array',
@ -10,7 +10,7 @@ export const relayerApiErrorResponseSchema = {
type: 'object', type: 'object',
properties: { properties: {
field: { type: 'string' }, field: { type: 'string' },
code: { type: 'number' }, code: { type: 'integer', minimum: 1000, maximum: 1006 },
reason: { type: 'string' }, reason: { type: 'string' },
}, },
required: ['field', 'code', 'reason'], required: ['field', 'code', 'reason'],

View File

@ -0,0 +1,13 @@
export const relayerApiFeeRecipientsResponseSchema = {
id: '/relayerApiFeeRecipientsResponseSchema',
type: 'object',
allOf: [
{ $ref: '/paginatedCollectionSchema' },
{
properties: {
records: { $ref: '/addressSchema' },
},
required: ['records'],
},
],
};

View File

@ -1,24 +0,0 @@
export const relayerApiFeesPayloadSchema = {
id: '/RelayerApiFeesPayload',
type: 'object',
properties: {
exchangeContractAddress: { $ref: '/Address' },
maker: { $ref: '/Address' },
taker: { $ref: '/Address' },
makerTokenAddress: { $ref: '/Address' },
takerTokenAddress: { $ref: '/Address' },
makerTokenAmount: { $ref: '/Number' },
takerTokenAmount: { $ref: '/Number' },
expirationUnixTimestampSec: { $ref: '/Number' },
salt: { $ref: '/Number' },
},
required: [
'exchangeContractAddress',
'maker',
'taker',
'makerTokenAddress',
'takerTokenAddress',
'expirationUnixTimestampSec',
'salt',
],
};

View File

@ -1,10 +0,0 @@
export const relayerApiFeesResponseSchema = {
id: '/RelayerApiFeesResponse',
type: 'object',
properties: {
makerFee: { $ref: '/Number' },
takerFee: { $ref: '/Number' },
feeRecipient: { $ref: '/Address' },
},
required: ['makerFee', 'takerFee', 'feeRecipient'],
};

View File

@ -1,23 +0,0 @@
export const relayerApiOrderbookChannelSubscribeSchema = {
id: '/RelayerApiOrderbookChannelSubscribe',
type: 'object',
properties: {
type: { enum: ['subscribe'] },
channel: { enum: ['orderbook'] },
requestId: { type: 'number' },
payload: { $ref: '/RelayerApiOrderbookChannelSubscribePayload' },
},
required: ['type', 'channel', 'requestId', 'payload'],
};
export const relayerApiOrderbookChannelSubscribePayload = {
id: '/RelayerApiOrderbookChannelSubscribePayload',
type: 'object',
properties: {
baseTokenAddress: { $ref: '/Address' },
quoteTokenAddress: { $ref: '/Address' },
snapshot: { type: 'boolean' },
limit: { type: 'number' },
},
required: ['baseTokenAddress', 'quoteTokenAddress'],
};

View File

@ -0,0 +1,24 @@
export const relayerApiOrderConfigPayloadSchema = {
id: '/relayerApiOrderConfigPayloadSchema',
type: 'object',
properties: {
makerAddress: { $ref: '/addressSchema' },
takerAddress: { $ref: '/addressSchema' },
makerAssetAmount: { $ref: '/numberSchema' },
takerAssetAmount: { $ref: '/numberSchema' },
makerAssetData: { $ref: '/hexSchema' },
takerAssetData: { $ref: '/hexSchema' },
exchangeAddress: { $ref: '/addressSchema' },
expirationTimeSeconds: { $ref: '/numberSchema' },
},
required: [
'makerAddress',
'takerAddress',
'makerAssetAmount',
'takerAssetAmount',
'makerAssetData',
'takerAssetData',
'exchangeAddress',
'expirationTimeSeconds',
],
};

View File

@ -0,0 +1,11 @@
export const relayerApiOrderConfigResponseSchema = {
id: '/relayerApiOrderConfigResponseSchema',
type: 'object',
properties: {
makerFee: { $ref: '/numberSchema' },
takerFee: { $ref: '/numberSchema' },
feeRecipientAddress: { $ref: '/addressSchema' },
senderAddress: { $ref: '/addressSchema' },
},
required: ['makerFee', 'takerFee', 'feeRecipientAddress', 'senderAddress'],
};

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