diff options
author | Hsuan Lee <boczeratul@gmail.com> | 2019-03-06 17:46:50 +0800 |
---|---|---|
committer | Hsuan Lee <boczeratul@gmail.com> | 2019-03-06 17:46:50 +0800 |
commit | 35703539d0f2b4ddb3b11d0de8c9634af59ab71f (patch) | |
tree | ae3731221dbbb3a6fa40060a8d916cfd3f738289 /packages/subproviders | |
parent | 92a1fde5b1ecd81b07cdb5bf0c9c1cd3544799db (diff) | |
download | dexon-0x-contracts-stable.tar.gz dexon-0x-contracts-stable.tar.zst dexon-0x-contracts-stable.zip |
Deploy @dexon-foundation/0x.jsstable
Diffstat (limited to 'packages/subproviders')
40 files changed, 0 insertions, 4117 deletions
diff --git a/packages/subproviders/.npmignore b/packages/subproviders/.npmignore deleted file mode 100644 index 44df80fad..000000000 --- a/packages/subproviders/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ -.* -yarn-error.log -/src/ -/scripts/ -test/ -tsconfig.json -/lib/src/monorepo_scripts/ diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json deleted file mode 100644 index 3d5bade1f..000000000 --- a/packages/subproviders/CHANGELOG.json +++ /dev/null @@ -1,504 +0,0 @@ -[ - { - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "timestamp": 1549452781, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - }, - { - "note": "Update ganache-core to v2.3.3", - "pr": 1518 - } - ], - "timestamp": 1549373905 - }, - { - "timestamp": 1547561734, - "version": "2.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547225310, - "version": "2.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547040760, - "version": "2.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544739608 - }, - { - "version": "2.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544570656 - }, - { - "timestamp": 1543401373, - "version": "2.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542821676, - "version": "2.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542208198, - "version": "2.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542134075, - "version": "2.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542028948, - "version": "2.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1541740904 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Add `MetamaskSubprovider` to handle inconsistent JSON RPC behaviour", - "pr": 1102 - }, - { - "note": "Add support for `eth_signTypedData` in wallets Mnemonic, Private and EthLightWallet", - "pr": 1102 - }, - { - "note": "Make web3-provider-engine types a 'dependency' so it's available to users of the library", - "pr": 1105 - } - ], - "timestamp": 1539871071 - }, - { - "version": "2.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1538693146 - }, - { - "timestamp": 1538157789, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537907159, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537875740, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537541580, - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1536142250, - "version": "2.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1535377027, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Export types: `PartialTxParams`, `JSONRPCRequestPayloadWithMethod`, `ECSignatureString`, `AccountFetchingConfigs`, `LedgerEthereumClientFactoryAsync`, `OnNextCompleted`, `MnemonicWalletSubproviderConfigs`, LedgerGetAddressResult, `JSONRPCRequestPayload`, `Provider`, `JSONRPCResponsePayload` and `JSONRPCErrorCallback`", - "pr": 924 - } - ], - "timestamp": 1535133899 - }, - { - "timestamp": 1534210131, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532619515, - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532614997, - "version": "1.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532605697, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532357734, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532043000, - "version": "1.0.0", - "changes": [ - { - "note": "Add `RpcSubprovider` with timeout", - "pr": 874 - }, - { - "note": "Add `EthLightwalletSubprovider`", - "pr": 775 - } - ] - }, - { - "timestamp": 1531919263, - "version": "0.10.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1529397769, - "version": "0.10.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1527009133, - "version": "0.10.3", - "changes": [ - { - "note": "Define engine type as Provider in setEngine", - "pr": 675 - } - ] - }, - { - "timestamp": 1527009133, - "version": "0.10.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525477860, - "version": "0.10.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.10.0", - "changes": [ - { - "note": "Upgrade web3-provider-engine to 14.0.4", - "pr": 555 - }, - { - "note": "Relax `to` validation in base wallet subprovider for transactions that deploy contracts", - "pr": 555 - } - ], - "timestamp": 1525428773 - }, - { - "version": "0.9.0", - "changes": [ - { - "note": "Refactor RedundantRPCSubprovider into RedundantSubprovider where it now accepts an array of subproviders rather then an array of RPC endpoints", - "pr": 500 - }, - { - "note": "Add PrivateKeySubprovider and refactor shared functionality into a base wallet subprovider", - "pr": 506 - }, - { - "note": "Add MnemonicWalletsubprovider, deprecating our truffle-hdwallet-provider fork", - "pr": 507 - }, - { - "note": "Support multiple addresses in ledger and mnemonic wallets", - "pr": 507 - }, - { - "note": "Refactors LedgerSubprovider such that explicitly setting the `pathIndex` is no longer required. Simply set the request `from` address as desired", - "pr": 507 - }, - { - "note": "Renamed derivationPath to baseDerivationPath.", - "pr": 507 - } - ], - "timestamp": 1523462196 - }, - { - "timestamp": 1522673609, - "version": "0.8.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.8.3", - "changes": [ - { - "note": "Introduce `JSONRPCRequestPayloadWithMethod` type", - "pr": 465 - }, - { - "note": "Export `ErrorCallback` type.", - "pr": 465 - } - ], - "timestamp": 1522658513 - }, - { - "version": "0.8.0", - "changes": [ - { - "note": "Export `GanacheSubprovider` and `Subprovider`", - "pr": 426 - }, - { - "note": "Make all subproviders to derive from `Subprovider`", - "pr": 426 - }, - { - "note": "Add types for `NextCallback`, `OnNextCompleted`", - "pr": 426 - }, - { - "note": "Ignore `ganache-core` dependency when using package in a browser environment." - } - ], - "timestamp": 1521298800 - }, - { - "version": "0.7.0", - "changes": [ - { - "note": "Updated legerco packages. Removed node-hid package as a dependency and make it an optional dependency. It is still used in integration tests but is causing problems for users on Linux distros.", - "pr": 437 - } - ], - "timestamp": 1520434800 - }, - { - "version": "0.6.0", - "changes": [ - { - "note": "Move web3 types from being a devDep to a dep since one cannot use this package without it", - "pr": 429 - }, - { - "note": "Add `numberOfAccounts` param to `LedgerSubprovider` method `getAccountsAsync`", - "pr": 432 - } - ], - "timestamp": 1520089200 - }, - { - "version": "0.5.0", - "changes": [ - { - "note": "Add EmptyWalletSubprovider and FakeGasEstimateSubprovider", - "pr": 392 - } - ], - "timestamp": 1518706800 - }, - { - "version": "0.4.1", - "changes": [ - { - "note": "Fix publishing issue where .npmignore was not properly excluding undesired content", - "pr": 389 - } - ], - "timestamp": 1518102000 - }, - { - "version": "0.4.0", - "changes": [ - { - "note": "Added NonceTrackerSubprovider", - "pr": 355 - }, - { - "note": "InjectedWeb3Subprovider accepts a Provider in the constructor, previously it was a Web3 object", - "pr": 363 - } - ], - "timestamp": 1517929200 - }, - { - "version": "0.3.6", - "changes": [ - { - "note": "Return a transaction hash from `_sendTransactionAsync`", - "pr": 303 - } - ], - "timestamp": 1517065200 - }, - { - "version": "0.3.0", - "changes": [ - { - "note": "Allow LedgerSubprovider to handle `eth_sign` in addition to `personal_sign` RPC requests" - } - ], - "timestamp": 1514386800 - }, - { - "version": "0.2.0", - "changes": [ - { - "note": "Improve the performance of address fetching", - "pr": 271 - } - ], - "timestamp": 1513695600 - } -] diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md deleted file mode 100644 index b3dfa757a..000000000 --- a/packages/subproviders/CHANGELOG.md +++ /dev/null @@ -1,210 +0,0 @@ -<!-- -changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly. -Edit the package's CHANGELOG.json file only. ---> - -CHANGELOG - -## v3.0.2 - _February 7, 2019_ - - * Dependencies updated - -## v3.0.1 - _February 6, 2019_ - - * Dependencies updated - -## v3.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - * Update ganache-core to v2.3.3 (#1518) - -## v2.1.11 - _January 15, 2019_ - - * Dependencies updated - -## v2.1.10 - _January 11, 2019_ - - * Dependencies updated - -## v2.1.9 - _January 9, 2019_ - - * Dependencies updated - -## v2.1.8 - _December 13, 2018_ - - * Dependencies updated - -## v2.1.7 - _December 11, 2018_ - - * Dependencies updated - -## v2.1.6 - _November 28, 2018_ - - * Dependencies updated - -## v2.1.5 - _November 21, 2018_ - - * Dependencies updated - -## v2.1.4 - _November 14, 2018_ - - * Dependencies updated - -## v2.1.3 - _November 13, 2018_ - - * Dependencies updated - -## v2.1.2 - _November 12, 2018_ - - * Dependencies updated - -## v2.1.1 - _November 9, 2018_ - - * Dependencies updated - -## v2.1.0 - _October 18, 2018_ - - * Add `MetamaskSubprovider` to handle inconsistent JSON RPC behaviour (#1102) - * Add support for `eth_signTypedData` in wallets Mnemonic, Private and EthLightWallet (#1102) - * Make web3-provider-engine types a 'dependency' so it's available to users of the library (#1105) - -## v2.0.7 - _October 4, 2018_ - - * Dependencies updated - -## v2.0.6 - _September 28, 2018_ - - * Dependencies updated - -## v2.0.5 - _September 25, 2018_ - - * Dependencies updated - -## v2.0.4 - _September 25, 2018_ - - * Dependencies updated - -## v2.0.3 - _September 21, 2018_ - - * Dependencies updated - -## v2.0.2 - _September 5, 2018_ - - * Dependencies updated - -## v2.0.1 - _August 27, 2018_ - - * Dependencies updated - -## v2.0.0 - _August 24, 2018_ - - * Export types: `PartialTxParams`, `JSONRPCRequestPayloadWithMethod`, `ECSignatureString`, `AccountFetchingConfigs`, `LedgerEthereumClientFactoryAsync`, `OnNextCompleted`, `MnemonicWalletSubproviderConfigs`, LedgerGetAddressResult, `JSONRPCRequestPayload`, `Provider`, `JSONRPCResponsePayload` and `JSONRPCErrorCallback` (#924) - -## v1.0.5 - _August 14, 2018_ - - * Dependencies updated - -## v1.0.4 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.3 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.2 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.1 - _July 23, 2018_ - - * Dependencies updated - -## v1.0.0 - _July 19, 2018_ - - * Add `RpcSubprovider` with timeout (#874) - * Add `EthLightwalletSubprovider` (#775) - -## v0.10.6 - _July 18, 2018_ - - * Dependencies updated - -## v0.10.4 - _June 19, 2018_ - - * Dependencies updated - -## v0.10.3 - _May 22, 2018_ - - * Define engine type as Provider in setEngine (#675) - -## v0.10.2 - _May 22, 2018_ - - * Dependencies updated - -## v0.10.1 - _May 4, 2018_ - - * Dependencies updated - -## v0.10.0 - _May 4, 2018_ - - * Upgrade web3-provider-engine to 14.0.4 (#555) - * Relax `to` validation in base wallet subprovider for transactions that deploy contracts (#555) - -## v0.9.0 - _April 11, 2018_ - - * Refactor RedundantRPCSubprovider into RedundantSubprovider where it now accepts an array of subproviders rather then an array of RPC endpoints (#500) - * Add PrivateKeySubprovider and refactor shared functionality into a base wallet subprovider (#506) - * Add MnemonicWalletsubprovider, deprecating our truffle-hdwallet-provider fork (#507) - * Support multiple addresses in ledger and mnemonic wallets (#507) - * Refactors LedgerSubprovider such that explicitly setting the `pathIndex` is no longer required. Simply set the request `from` address as desired (#507) - * Renamed derivationPath to baseDerivationPath. (#507) - -## v0.8.4 - _April 2, 2018_ - - * Dependencies updated - -## v0.8.3 - _April 2, 2018_ - - * Introduce `JSONRPCRequestPayloadWithMethod` type (#465) - * Export `ErrorCallback` type. (#465) - -## v0.8.0 - _March 17, 2018_ - - * Export `GanacheSubprovider` and `Subprovider` (#426) - * Make all subproviders to derive from `Subprovider` (#426) - * Add types for `NextCallback`, `OnNextCompleted` (#426) - * Ignore `ganache-core` dependency when using package in a browser environment. - -## v0.7.0 - _March 7, 2018_ - - * Updated legerco packages. Removed node-hid package as a dependency and make it an optional dependency. It is still used in integration tests but is causing problems for users on Linux distros. (#437) - -## v0.6.0 - _March 3, 2018_ - - * Move web3 types from being a devDep to a dep since one cannot use this package without it (#429) - * Add `numberOfAccounts` param to `LedgerSubprovider` method `getAccountsAsync` (#432) - -## v0.5.0 - _February 15, 2018_ - - * Add EmptyWalletSubprovider and FakeGasEstimateSubprovider (#392) - -## v0.4.1 - _February 8, 2018_ - - * Fix publishing issue where .npmignore was not properly excluding undesired content (#389) - -## v0.4.0 - _February 6, 2018_ - - * Added NonceTrackerSubprovider (#355) - * InjectedWeb3Subprovider accepts a Provider in the constructor, previously it was a Web3 object (#363) - -## v0.3.6 - _January 27, 2018_ - - * Return a transaction hash from `_sendTransactionAsync` (#303) - -## v0.3.0 - _December 27, 2017_ - - * Allow LedgerSubprovider to handle `eth_sign` in addition to `personal_sign` RPC requests - -## v0.2.0 - _December 19, 2017_ - - * Improve the performance of address fetching (#271) diff --git a/packages/subproviders/README.md b/packages/subproviders/README.md deleted file mode 100644 index b0d77284b..000000000 --- a/packages/subproviders/README.md +++ /dev/null @@ -1,100 +0,0 @@ -## @0x/subproviders - -A few useful web3 subproviders including a LedgerSubprovider useful for adding Ledger Nano S support. - -We have written up a [Wiki](https://0xproject.com/wiki#Web3-Provider-Examples) article detailing some use cases of this subprovider package. - -### Read the [Documentation](https://0xproject.com/docs/subproviders). - -## Installation - -``` -yarn add @0x/subproviders -``` - -If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`: - -```json -"compilerOptions": { - "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"], -} -``` - -## Contributing - -We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository. - -Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. - -### Install dependencies - -If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: - -```bash -yarn config set workspaces-experimental true -``` - -Then install dependencies - -```bash -yarn install -``` - -### Build - -To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: - -```bash -PKG=@0x/subproviders yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/subproviders yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run tests - -#### Unit tests - -```bash -yarn run test:unit -``` - -#### Integration tests - -In order to run the integration tests, make sure you have a Ledger Nano S available. - -- Setup your Ledger with the development mnemonic seed: `concert load couple harbor equip island argue ramp clarify fence smart topic` -- Plug it into your computer -- Unlock the device -- Open the on-device Ethereum app -- Make sure "browser support" and "contract data" are disabled -- Start [TestRPC](https://github.com/trufflesuite/ganache-cli) locally at port `8545` - -Then run: - -``` -yarn test:integration -``` - -**Note:** We assume a derivation path of `m/44'/60'/0'/0` which is already configured in the tests. With this setup and derivation path, your first account should be `0x5409ed021d9299bf6814279a6a1411a7e866a631`, exactly like TestRPC. - -#### All tests - -```bash -yarn run test:all -``` diff --git a/packages/subproviders/coverage/.gitkeep b/packages/subproviders/coverage/.gitkeep deleted file mode 100644 index e69de29bb..000000000 --- a/packages/subproviders/coverage/.gitkeep +++ /dev/null diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json deleted file mode 100644 index a783bb5a2..000000000 --- a/packages/subproviders/package.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "@0x/subproviders", - "version": "3.0.2", - "engines": { - "node": ">=6.12" - }, - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "license": "Apache-2.0", - "scripts": { - "build": "tsc -b", - "build:ci": "yarn build", - "clean": "shx rm -rf lib generated_docs", - "lint": "tslint --format stylish --project .", - "run_mocha_unit": "mocha --require source-map-support/register --require make-promises-safe lib/test/unit/**/*_test.js --timeout 10000 --bail --exit", - "run_mocha_integration": "mocha --require source-map-support/register --require make-promises-safe lib/test/integration/**/*_test.js --timeout 10000 --bail --exit", - "test": "npm run test:unit", - "test:unit:coverage": "nyc npm run test:unit --all && yarn coverage:report:lcov", - "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", - "test:circleci": "npm run test:unit:coverage", - "test:all": "run-s test:unit test:integration", - "test:unit": "run-s clean build run_mocha_unit", - "test:integration": "run-s clean build run_mocha_integration", - "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "postpublish": { - "assets": [] - } - }, - "dependencies": { - "@0x/assert": "^2.0.2", - "@0x/types": "^2.0.2", - "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", - "@ledgerhq/hw-app-eth": "^4.3.0", - "@ledgerhq/hw-transport-u2f": "4.24.0", - "@types/eth-lightwallet": "^3.0.0", - "@types/ganache-core": "^2.1.2", - "@types/hdkey": "^0.7.0", - "@types/web3-provider-engine": "^14.0.0", - "bip39": "^2.5.0", - "bn.js": "^4.11.8", - "eth-lightwallet": "^3.0.1", - "ethereum-types": "^2.0.0", - "ethereumjs-tx": "^1.3.5", - "ethereumjs-util": "^5.1.1", - "ganache-core": "^2.3.3", - "hdkey": "^0.7.1", - "json-rpc-error": "2.0.0", - "lodash": "^4.17.11", - "semaphore-async-await": "^1.5.1", - "web3-provider-engine": "14.0.6" - }, - "devDependencies": { - "@0x/tslint-config": "^3.0.0", - "@types/bip39": "^2.4.0", - "@types/bn.js": "^4.11.0", - "@types/ethereumjs-tx": "^1.0.0", - "@types/hdkey": "^0.7.0", - "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", - "@types/node": "*", - "@types/sinon": "^2.2.2", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "dirty-chai": "^2.0.1", - "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", - "npm-run-all": "^4.1.2", - "nyc": "^11.0.1", - "shx": "^0.2.2", - "sinon": "^4.0.0", - "tslint": "5.11.0", - "typedoc": "0.13.0", - "typescript": "3.0.1", - "webpack": "^4.20.2" - }, - "optionalDependencies": { - "@ledgerhq/hw-transport-node-hid": "^4.3.0" - }, - "publishConfig": { - "access": "public" - }, - "browser": { - "ganache-core": false - } -} diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts deleted file mode 100644 index 3cbf84e37..000000000 --- a/packages/subproviders/src/globals.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -declare module '*.json' { - const json: any; - /* tslint:disable */ - export default json; - /* tslint:enable */ -} -declare module 'web3-provider-engine/util/rpc-cache-utils' { - class ProviderEngineRpcUtils { - public static blockTagForPayload(payload: any): string | null; - } - export = ProviderEngineRpcUtils; -} -declare module 'web3-provider-engine/subproviders/fixture' { - import { JSONRPCRequestPayload, JSONRPCResponsePayload } from 'ethereum-types'; - class FixtureSubprovider { - constructor(staticResponses: any); - public handleRequest( - payload: JSONRPCRequestPayload, - next: () => void, - end: (err: Error | null, data?: JSONRPCResponsePayload) => void, - ): void; - } - export = FixtureSubprovider; -} diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts deleted file mode 100644 index 050027f96..000000000 --- a/packages/subproviders/src/index.ts +++ /dev/null @@ -1,59 +0,0 @@ -import Eth from '@ledgerhq/hw-app-eth'; -import TransportU2F from '@ledgerhq/hw-transport-u2f'; -export import Web3ProviderEngine = require('web3-provider-engine'); - -import { LedgerEthereumClient } from './types'; - -/** - * A factory method for creating a LedgerEthereumClient usable in a browser context. - * @return LedgerEthereumClient A browser client for the LedgerSubprovider - */ -export async function ledgerEthereumBrowserClientFactoryAsync(): Promise<LedgerEthereumClient> { - const ledgerConnection = await TransportU2F.create(); - const ledgerEthClient = new Eth(ledgerConnection); - return ledgerEthClient; -} - -export { prependSubprovider } from './utils/subprovider_utils'; - -export { EmptyWalletSubprovider } from './subproviders/empty_wallet_subprovider'; -export { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_subprovider'; -export { SignerSubprovider } from './subproviders/signer'; -export { RedundantSubprovider } from './subproviders/redundant_subprovider'; -export { LedgerSubprovider } from './subproviders/ledger'; -export { RPCSubprovider } from './subproviders/rpc_subprovider'; -export { GanacheSubprovider } from './subproviders/ganache'; -export { Subprovider } from './subproviders/subprovider'; -export { NonceTrackerSubprovider } from './subproviders/nonce_tracker'; -export { PrivateKeyWalletSubprovider } from './subproviders/private_key_wallet'; -export { MnemonicWalletSubprovider } from './subproviders/mnemonic_wallet'; -export { MetamaskSubprovider } from './subproviders/metamask_subprovider'; -export { EthLightwalletSubprovider } from './subproviders/eth_lightwallet_subprovider'; - -export { - Callback, - ErrorCallback, - NextCallback, - LedgerCommunicationClient, - LedgerEthereumClient, - NonceSubproviderErrors, - LedgerSubproviderConfigs, - PartialTxParams, - JSONRPCRequestPayloadWithMethod, - ECSignatureString, - AccountFetchingConfigs, - LedgerEthereumClientFactoryAsync, - OnNextCompleted, - MnemonicWalletSubproviderConfigs, - LedgerGetAddressResult, -} from './types'; - -export { ECSignature, EIP712Object, EIP712ObjectValue, EIP712TypedData, EIP712Types, EIP712Parameter } from '@0x/types'; - -export { - JSONRPCRequestPayload, - Provider, - JSONRPCResponsePayload, - JSONRPCErrorCallback, - JSONRPCResponseError, -} from 'ethereum-types'; diff --git a/packages/subproviders/src/subproviders/base_wallet_subprovider.ts b/packages/subproviders/src/subproviders/base_wallet_subprovider.ts deleted file mode 100644 index e9d104074..000000000 --- a/packages/subproviders/src/subproviders/base_wallet_subprovider.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { assert } from '@0x/assert'; -import { addressUtils } from '@0x/utils'; -import { JSONRPCRequestPayload, JSONRPCResponsePayload } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { Callback, ErrorCallback, PartialTxParams, WalletSubproviderErrors } from '../types'; - -import { Subprovider } from './subprovider'; - -export abstract class BaseWalletSubprovider extends Subprovider { - protected static _validateTxParams(txParams: PartialTxParams): void { - if (!_.isUndefined(txParams.to)) { - assert.isETHAddressHex('to', txParams.to); - } - assert.isHexString('nonce', txParams.nonce); - } - private static _validateSender(sender: string): void { - if (_.isUndefined(sender) || !addressUtils.isAddress(sender)) { - throw new Error(WalletSubproviderErrors.SenderInvalidOrNotSupplied); - } - } - - public abstract async getAccountsAsync(): Promise<string[]>; - public abstract async signTransactionAsync(txParams: PartialTxParams): Promise<string>; - public abstract async signPersonalMessageAsync(data: string, address: string): Promise<string>; - public abstract async signTypedDataAsync(address: string, typedData: any): Promise<string>; - - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback): Promise<void> { - let accounts; - let txParams; - let address; - let typedData; - switch (payload.method) { - case 'eth_coinbase': - try { - accounts = await this.getAccountsAsync(); - end(null, accounts[0]); - } catch (err) { - end(err); - } - return; - - case 'eth_accounts': - try { - accounts = await this.getAccountsAsync(); - end(null, accounts); - } catch (err) { - end(err); - } - return; - - case 'eth_sendTransaction': - txParams = payload.params[0]; - try { - BaseWalletSubprovider._validateSender(txParams.from); - const filledParams = await this._populateMissingTxParamsAsync(txParams); - const signedTx = await this.signTransactionAsync(filledParams); - const response = await this._emitSendTransactionAsync(signedTx); - end(null, response.result); - } catch (err) { - end(err); - } - return; - - case 'eth_signTransaction': - txParams = payload.params[0]; - try { - const filledParams = await this._populateMissingTxParamsAsync(txParams); - const signedTx = await this.signTransactionAsync(filledParams); - const result = { - raw: signedTx, - tx: txParams, - }; - end(null, result); - } catch (err) { - end(err); - } - return; - - case 'eth_sign': - case 'personal_sign': - const data = payload.method === 'eth_sign' ? payload.params[1] : payload.params[0]; - address = payload.method === 'eth_sign' ? payload.params[0] : payload.params[1]; - try { - const ecSignatureHex = await this.signPersonalMessageAsync(data, address); - end(null, ecSignatureHex); - } catch (err) { - end(err); - } - return; - case 'eth_signTypedData': - [address, typedData] = payload.params; - try { - const signature = await this.signTypedDataAsync(address, typedData); - end(null, signature); - } catch (err) { - end(err); - } - return; - - default: - next(); - return; - } - } - private async _emitSendTransactionAsync(signedTx: string): Promise<JSONRPCResponsePayload> { - const payload = { - method: 'eth_sendRawTransaction', - params: [signedTx], - }; - const result = await this.emitPayloadAsync(payload); - return result; - } - private async _populateMissingTxParamsAsync(partialTxParams: PartialTxParams): Promise<PartialTxParams> { - let txParams = partialTxParams; - if (_.isUndefined(partialTxParams.gasPrice)) { - const gasPriceResult = await this.emitPayloadAsync({ - method: 'eth_gasPrice', - params: [], - }); - const gasPrice = gasPriceResult.result.toString(); - txParams = { ...txParams, gasPrice }; - } - if (_.isUndefined(partialTxParams.nonce)) { - const nonceResult = await this.emitPayloadAsync({ - method: 'eth_getTransactionCount', - params: [partialTxParams.from, 'pending'], - }); - const nonce = nonceResult.result; - txParams = { ...txParams, nonce }; - } - if (_.isUndefined(partialTxParams.gas)) { - const gasResult = await this.emitPayloadAsync({ - method: 'eth_estimateGas', - params: [partialTxParams], - }); - const gas = gasResult.result.toString(); - txParams = { ...txParams, gas }; - } - return txParams; - } -} diff --git a/packages/subproviders/src/subproviders/empty_wallet_subprovider.ts b/packages/subproviders/src/subproviders/empty_wallet_subprovider.ts deleted file mode 100644 index 4268c67bd..000000000 --- a/packages/subproviders/src/subproviders/empty_wallet_subprovider.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { JSONRPCRequestPayload } from 'ethereum-types'; - -import { Callback, ErrorCallback } from '../types'; - -import { Subprovider } from './subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * It intercepts the `eth_accounts` JSON RPC requests and never returns any addresses when queried. - */ -export class EmptyWalletSubprovider extends Subprovider { - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:prefer-function-over-method async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback): Promise<void> { - switch (payload.method) { - case 'eth_accounts': - end(null, []); - return; - - default: - next(); - return; - } - } -} diff --git a/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts b/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts deleted file mode 100644 index 15cd713af..000000000 --- a/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { EIP712TypedData } from '@0x/types'; -import * as lightwallet from 'eth-lightwallet'; - -import { PartialTxParams } from '../types'; - -import { BaseWalletSubprovider } from './base_wallet_subprovider'; -import { PrivateKeyWalletSubprovider } from './private_key_wallet'; - -/* - * This class implements the web3-provider-engine subprovider interface and forwards - * requests involving user accounts and signing operations to eth-lightwallet - * - * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js - */ -export class EthLightwalletSubprovider extends BaseWalletSubprovider { - private readonly _keystore: lightwallet.keystore; - private readonly _pwDerivedKey: Uint8Array; - /** - * Instantiate an EthLightwalletSubprovider - * @param keystore The EthLightWallet keystore you wish to use - * @param pwDerivedKey The password derived key to use - * @return EthLightwalletSubprovider instance - */ - constructor(keystore: lightwallet.keystore, pwDerivedKey: Uint8Array) { - super(); - this._keystore = keystore; - this._pwDerivedKey = pwDerivedKey; - } - /** - * Retrieve the accounts associated with the eth-lightwallet instance. - * This method is implicitly called when issuing a `eth_accounts` JSON RPC request - * via your providerEngine instance. - * - * @return An array of accounts - */ - public async getAccountsAsync(): Promise<string[]> { - const accounts = this._keystore.getAddresses(); - return accounts; - } - /** - * Signs a transaction with the account specificed by the `from` field in txParams. - * If you've added this Subprovider to your app's provider, you can simply send - * an `eth_sendTransaction` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param txParams Parameters of the transaction to sign - * @return Signed transaction hex string - */ - public async signTransactionAsync(txParams: PartialTxParams): Promise<string> { - // Lightwallet loses the chain id information when hex encoding the transaction - // this results in a different signature on certain networks. PrivateKeyWallet - // respects this as it uses the parameters passed in - let privateKey = this._keystore.exportPrivateKey(txParams.from, this._pwDerivedKey); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKey); - privateKey = ''; - const privateKeySignature = await privateKeyWallet.signTransactionAsync(txParams); - return privateKeySignature; - } - /** - * Sign a personal Ethereum signed message. The signing account will be the account - * associated with the provided address. - * If you've added this Subprovider to your app's provider, you can simply send an `eth_sign` - * or `personal_sign` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param data Hex string message to sign - * @param address Address of the account to sign with - * @return Signature hex string (order: rsv) - */ - public async signPersonalMessageAsync(data: string, address: string): Promise<string> { - let privateKey = this._keystore.exportPrivateKey(address, this._pwDerivedKey); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKey); - privateKey = ''; - const result = privateKeyWallet.signPersonalMessageAsync(data, address); - return result; - } - /** - * Sign an EIP712 Typed Data message. The signing address will associated with the provided address. - * If you've added this Subprovider to your app's provider, you can simply send an `eth_signTypedData` - * JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param address Address of the account to sign with - * @param data the typed data object - * @return Signature hex string (order: rsv) - */ - public async signTypedDataAsync(address: string, typedData: EIP712TypedData): Promise<string> { - let privateKey = this._keystore.exportPrivateKey(address, this._pwDerivedKey); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKey); - privateKey = ''; - const result = privateKeyWallet.signTypedDataAsync(address, typedData); - return result; - } -} diff --git a/packages/subproviders/src/subproviders/fake_gas_estimate_subprovider.ts b/packages/subproviders/src/subproviders/fake_gas_estimate_subprovider.ts deleted file mode 100644 index bc1b34aba..000000000 --- a/packages/subproviders/src/subproviders/fake_gas_estimate_subprovider.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { JSONRPCRequestPayload } from 'ethereum-types'; - -import { Callback, ErrorCallback } from '../types'; - -import { Subprovider } from './subprovider'; - -// HACK: We need this so that our tests don't use testrpc gas estimation which sometimes kills the node. -// Source: https://github.com/trufflesuite/ganache-cli/issues/417 -// Source: https://github.com/trufflesuite/ganache-cli/issues/437 -// Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * It intercepts the `eth_estimateGas` JSON RPC call and always returns a constant gas amount when queried. - */ -export class FakeGasEstimateSubprovider extends Subprovider { - private readonly _constantGasAmount: number; - /** - * Instantiates an instance of the FakeGasEstimateSubprovider - * @param constantGasAmount The constant gas amount you want returned - */ - constructor(constantGasAmount: number) { - super(); - this._constantGasAmount = constantGasAmount; - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:prefer-function-over-method async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback): Promise<void> { - switch (payload.method) { - case 'eth_estimateGas': - end(null, this._constantGasAmount); - return; - - default: - next(); - return; - } - } -} diff --git a/packages/subproviders/src/subproviders/ganache.ts b/packages/subproviders/src/subproviders/ganache.ts deleted file mode 100644 index 2b8544f8b..000000000 --- a/packages/subproviders/src/subproviders/ganache.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { JSONRPCRequestPayload, Provider } from 'ethereum-types'; -import * as Ganache from 'ganache-core'; - -import { Callback, ErrorCallback } from '../types'; - -import { Subprovider } from './subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * It intercepts all JSON RPC requests and relays them to an in-process ganache instance. - */ -export class GanacheSubprovider extends Subprovider { - private readonly _ganacheProvider: Provider; - /** - * Instantiates a GanacheSubprovider - * @param opts The desired opts with which to instantiate the Ganache provider - */ - constructor(opts: Ganache.GanacheOpts) { - super(); - this._ganacheProvider = Ganache.provider(opts); - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param _next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:prefer-function-over-method async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, _next: Callback, end: ErrorCallback): Promise<void> { - this._ganacheProvider.sendAsync(payload, (err: Error | null, result: any) => { - end(err, result && result.result); - }); - } -} diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts deleted file mode 100644 index b5ca10ce1..000000000 --- a/packages/subproviders/src/subproviders/ledger.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { assert } from '@0x/assert'; -import { addressUtils } from '@0x/utils'; -import EthereumTx = require('ethereumjs-tx'); -import ethUtil = require('ethereumjs-util'); -import HDNode = require('hdkey'); -import * as _ from 'lodash'; -import { Lock } from 'semaphore-async-await'; - -import { - DerivedHDKeyInfo, - LedgerEthereumClient, - LedgerEthereumClientFactoryAsync, - LedgerSubproviderConfigs, - LedgerSubproviderErrors, - PartialTxParams, - WalletSubproviderErrors, -} from '../types'; -import { walletUtils } from '../utils/wallet_utils'; - -import { BaseWalletSubprovider } from './base_wallet_subprovider'; - -const DEFAULT_BASE_DERIVATION_PATH = `44'/60'/0'`; -const ASK_FOR_ON_DEVICE_CONFIRMATION = false; -const SHOULD_GET_CHAIN_CODE = true; -const DEFAULT_NUM_ADDRESSES_TO_FETCH = 10; -const DEFAULT_ADDRESS_SEARCH_LIMIT = 1000; - -/** - * Subprovider for interfacing with a user's [Ledger Nano S](https://www.ledgerwallet.com/products/ledger-nano-s). - * This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and - * re-routes them to a Ledger device plugged into the users computer. - */ -export class LedgerSubprovider extends BaseWalletSubprovider { - // tslint:disable-next-line:no-unused-variable - private readonly _connectionLock = new Lock(); - private readonly _networkId: number; - private _baseDerivationPath: string; - private readonly _ledgerEthereumClientFactoryAsync: LedgerEthereumClientFactoryAsync; - private _ledgerClientIfExists?: LedgerEthereumClient; - private readonly _shouldAlwaysAskForConfirmation: boolean; - private readonly _addressSearchLimit: number; - /** - * Instantiates a LedgerSubprovider. Defaults to derivationPath set to `44'/60'/0'`. - * TestRPC/Ganache defaults to `m/44'/60'/0'/0`, so set this in the configs if desired. - * @param config Several available configurations - * @return LedgerSubprovider instance - */ - constructor(config: LedgerSubproviderConfigs) { - super(); - this._networkId = config.networkId; - this._ledgerEthereumClientFactoryAsync = config.ledgerEthereumClientFactoryAsync; - this._baseDerivationPath = config.baseDerivationPath || DEFAULT_BASE_DERIVATION_PATH; - this._shouldAlwaysAskForConfirmation = - !_.isUndefined(config.accountFetchingConfigs) && - !_.isUndefined(config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation) - ? config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation - : ASK_FOR_ON_DEVICE_CONFIRMATION; - this._addressSearchLimit = - !_.isUndefined(config.accountFetchingConfigs) && - !_.isUndefined(config.accountFetchingConfigs.addressSearchLimit) - ? config.accountFetchingConfigs.addressSearchLimit - : DEFAULT_ADDRESS_SEARCH_LIMIT; - } - /** - * Retrieve the set derivation path - * @returns derivation path - */ - public getPath(): string { - return this._baseDerivationPath; - } - /** - * Set a desired derivation path when computing the available user addresses - * @param basDerivationPath The desired derivation path (e.g `44'/60'/0'`) - */ - public setPath(basDerivationPath: string): void { - this._baseDerivationPath = basDerivationPath; - } - /** - * Retrieve a users Ledger accounts. The accounts are derived from the derivationPath, - * master public key and chain code. Because of this, you can request as many accounts - * as you wish and it only requires a single request to the Ledger device. This method - * is automatically called when issuing a `eth_accounts` JSON RPC request via your providerEngine - * instance. - * @param numberOfAccounts Number of accounts to retrieve (default: 10) - * @return An array of accounts - */ - public async getAccountsAsync(numberOfAccounts: number = DEFAULT_NUM_ADDRESSES_TO_FETCH): Promise<string[]> { - const initialDerivedKeyInfo = await this._initialDerivedKeyInfoAsync(); - const derivedKeyInfos = walletUtils.calculateDerivedHDKeyInfos(initialDerivedKeyInfo, numberOfAccounts); - const accounts = _.map(derivedKeyInfos, k => k.address); - return accounts; - } - /** - * Signs a transaction on the Ledger with the account specificed by the `from` field in txParams. - * If you've added the LedgerSubprovider to your app's provider, you can simply send an `eth_sendTransaction` - * JSON RPC request, and this method will be called auto-magically. If you are not using this via a ProviderEngine - * instance, you can call it directly. - * @param txParams Parameters of the transaction to sign - * @return Signed transaction hex string - */ - public async signTransactionAsync(txParams: PartialTxParams): Promise<string> { - LedgerSubprovider._validateTxParams(txParams); - if (_.isUndefined(txParams.from) || !addressUtils.isAddress(txParams.from)) { - throw new Error(WalletSubproviderErrors.FromAddressMissingOrInvalid); - } - const initialDerivedKeyInfo = await this._initialDerivedKeyInfoAsync(); - const derivedKeyInfo = this._findDerivedKeyInfoForAddress(initialDerivedKeyInfo, txParams.from); - - this._ledgerClientIfExists = await this._createLedgerClientAsync(); - - const tx = new EthereumTx(txParams); - - // Set the EIP155 bits - const vIndex = 6; - tx.raw[vIndex] = Buffer.from([this._networkId]); // v - const rIndex = 7; - tx.raw[rIndex] = Buffer.from([]); // r - const sIndex = 8; - tx.raw[sIndex] = Buffer.from([]); // s - - const txHex = tx.serialize().toString('hex'); - try { - const fullDerivationPath = derivedKeyInfo.derivationPath; - const result = await this._ledgerClientIfExists.signTransaction(fullDerivationPath, txHex); - // Store signature in transaction - tx.r = Buffer.from(result.r, 'hex'); - tx.s = Buffer.from(result.s, 'hex'); - tx.v = Buffer.from(result.v, 'hex'); - - // EIP155: v should be chain_id * 2 + {35, 36} - const eip55Constant = 35; - const signedChainId = Math.floor((tx.v[0] - eip55Constant) / 2); - if (signedChainId !== this._networkId) { - await this._destroyLedgerClientAsync(); - const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware); - throw err; - } - - const signedTxHex = `0x${tx.serialize().toString('hex')}`; - await this._destroyLedgerClientAsync(); - return signedTxHex; - } catch (err) { - await this._destroyLedgerClientAsync(); - throw err; - } - } - /** - * Sign a personal Ethereum signed message. The signing account will be the account - * associated with the provided address. - * The Ledger adds the Ethereum signed message prefix on-device. If you've added - * the LedgerSubprovider to your app's provider, you can simply send an `eth_sign` - * or `personal_sign` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param data Hex string message to sign - * @param address Address of the account to sign with - * @return Signature hex string (order: rsv) - */ - public async signPersonalMessageAsync(data: string, address: string): Promise<string> { - if (_.isUndefined(data)) { - throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage); - } - assert.isHexString('data', data); - assert.isETHAddressHex('address', address); - const initialDerivedKeyInfo = await this._initialDerivedKeyInfoAsync(); - const derivedKeyInfo = this._findDerivedKeyInfoForAddress(initialDerivedKeyInfo, address); - - this._ledgerClientIfExists = await this._createLedgerClientAsync(); - try { - const fullDerivationPath = derivedKeyInfo.derivationPath; - const result = await this._ledgerClientIfExists.signPersonalMessage( - fullDerivationPath, - ethUtil.stripHexPrefix(data), - ); - const lowestValidV = 27; - const v = result.v - lowestValidV; - const hexBase = 16; - let vHex = v.toString(hexBase); - if (vHex.length < 2) { - vHex = `0${v}`; - } - const signature = `0x${result.r}${result.s}${vHex}`; - await this._destroyLedgerClientAsync(); - return signature; - } catch (err) { - await this._destroyLedgerClientAsync(); - throw err; - } - } - /** - * eth_signTypedData is currently not supported on Ledger devices. - * @param address Address of the account to sign with - * @param data the typed data object - * @return Signature hex string (order: rsv) - */ - // tslint:disable-next-line:prefer-function-over-method - public async signTypedDataAsync(address: string, typedData: any): Promise<string> { - throw new Error(WalletSubproviderErrors.MethodNotSupported); - } - private async _createLedgerClientAsync(): Promise<LedgerEthereumClient> { - await this._connectionLock.acquire(); - if (!_.isUndefined(this._ledgerClientIfExists)) { - this._connectionLock.release(); - throw new Error(LedgerSubproviderErrors.MultipleOpenConnectionsDisallowed); - } - const ledgerEthereumClient = await this._ledgerEthereumClientFactoryAsync(); - this._connectionLock.release(); - return ledgerEthereumClient; - } - private async _destroyLedgerClientAsync(): Promise<void> { - await this._connectionLock.acquire(); - if (_.isUndefined(this._ledgerClientIfExists)) { - this._connectionLock.release(); - return; - } - await this._ledgerClientIfExists.transport.close(); - this._ledgerClientIfExists = undefined; - this._connectionLock.release(); - } - private async _initialDerivedKeyInfoAsync(): Promise<DerivedHDKeyInfo> { - this._ledgerClientIfExists = await this._createLedgerClientAsync(); - - const parentKeyDerivationPath = `m/${this._baseDerivationPath}`; - let ledgerResponse; - try { - ledgerResponse = await this._ledgerClientIfExists.getAddress( - parentKeyDerivationPath, - this._shouldAlwaysAskForConfirmation, - SHOULD_GET_CHAIN_CODE, - ); - } finally { - await this._destroyLedgerClientAsync(); - } - const hdKey = new HDNode(); - hdKey.publicKey = new Buffer(ledgerResponse.publicKey, 'hex'); - hdKey.chainCode = new Buffer(ledgerResponse.chainCode, 'hex'); - const address = walletUtils.addressOfHDKey(hdKey); - const initialDerivedKeyInfo = { - hdKey, - address, - derivationPath: parentKeyDerivationPath, - baseDerivationPath: this._baseDerivationPath, - }; - return initialDerivedKeyInfo; - } - private _findDerivedKeyInfoForAddress(initalHDKey: DerivedHDKeyInfo, address: string): DerivedHDKeyInfo { - const matchedDerivedKeyInfo = walletUtils.findDerivedKeyInfoForAddressIfExists( - address, - initalHDKey, - this._addressSearchLimit, - ); - if (_.isUndefined(matchedDerivedKeyInfo)) { - throw new Error(`${WalletSubproviderErrors.AddressNotFound}: ${address}`); - } - return matchedDerivedKeyInfo; - } -} diff --git a/packages/subproviders/src/subproviders/metamask_subprovider.ts b/packages/subproviders/src/subproviders/metamask_subprovider.ts deleted file mode 100644 index ba207d4cc..000000000 --- a/packages/subproviders/src/subproviders/metamask_subprovider.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { marshaller, Web3Wrapper } from '@0x/web3-wrapper'; -import { JSONRPCRequestPayload, Provider } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; - -import { Callback, ErrorCallback } from '../types'; - -import { Subprovider } from './subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) - * subprovider interface and the provider sendAsync interface. - * It handles inconsistencies with Metamask implementations of various JSON RPC methods. - * It forwards JSON RPC requests involving the domain of a signer (getAccounts, - * sendTransaction, signMessage etc...) to the provider instance supplied at instantiation. All other requests - * are passed onwards for subsequent subproviders to handle. - */ -export class MetamaskSubprovider extends Subprovider { - private readonly _web3Wrapper: Web3Wrapper; - private readonly _provider: Provider; - /** - * Instantiates a new MetamaskSubprovider - * @param provider Web3 provider that should handle all user account related requests - */ - constructor(provider: Provider) { - super(); - this._web3Wrapper = new Web3Wrapper(provider); - this._provider = provider; - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:prefer-function-over-method async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback): Promise<void> { - let message; - let address; - switch (payload.method) { - case 'web3_clientVersion': - try { - const nodeVersion = await this._web3Wrapper.getNodeVersionAsync(); - end(null, nodeVersion); - } catch (err) { - end(err); - } - return; - case 'eth_accounts': - try { - const accounts = await this._web3Wrapper.getAvailableAddressesAsync(); - end(null, accounts); - } catch (err) { - end(err); - } - return; - case 'eth_sendTransaction': - const [txParams] = payload.params; - try { - const txData = marshaller.unmarshalTxData(txParams); - const txHash = await this._web3Wrapper.sendTransactionAsync(txData); - end(null, txHash); - } catch (err) { - end(err); - } - return; - case 'eth_sign': - [address, message] = payload.params; - try { - // Metamask incorrectly implements eth_sign and does not prefix the message as per the spec - // Source: https://github.com/MetaMask/metamask-extension/commit/a9d36860bec424dcee8db043d3e7da6a5ff5672e - const msgBuff = ethUtil.toBuffer(message); - const prefixedMsgBuff = ethUtil.hashPersonalMessage(msgBuff); - const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff); - const signature = await this._web3Wrapper.signMessageAsync(address, prefixedMsgHex); - signature ? end(null, signature) : end(new Error('Error performing eth_sign'), null); - } catch (err) { - end(err); - } - return; - case 'eth_signTypedData': - case 'eth_signTypedData_v3': - [address, message] = payload.params; - try { - // Metamask supports multiple versions and has namespaced signTypedData to v3 for an indeterminate period of time. - // eth_signTypedData is mapped to an older implementation before the spec was finalized. - // Source: https://github.com/MetaMask/metamask-extension/blob/c49d854b55b3efd34c7fd0414b76f7feaa2eec7c/app/scripts/metamask-controller.js#L1262 - // and expects message to be serialised as JSON - const messageJSON = JSON.stringify(message); - const signature = await this._web3Wrapper.sendRawPayloadAsync<string>({ - method: 'eth_signTypedData_v3', - params: [address, messageJSON], - }); - signature ? end(null, signature) : end(new Error('Error performing eth_signTypedData'), null); - } catch (err) { - end(err); - } - return; - default: - next(); - return; - } - } - /** - * This method conforms to the provider sendAsync interface. - * Allowing the MetamaskSubprovider to be used as a generic provider (outside of Web3ProviderEngine) with the - * addition of wrapping the inconsistent Metamask behaviour - * @param payload JSON RPC payload - * @return The contents nested under the result key of the response body - */ - public sendAsync(payload: JSONRPCRequestPayload, callback: ErrorCallback): void { - void this.handleRequest( - payload, - // handleRequest has decided to not handle this, so fall through to the provider - () => { - const sendAsync = this._provider.sendAsync.bind(this._provider); - sendAsync(payload, callback); - }, - // handleRequest has called end and will handle this - (err, data) => { - err ? callback(err) : callback(null, { ...payload, result: data }); - }, - ); - } -} diff --git a/packages/subproviders/src/subproviders/mnemonic_wallet.ts b/packages/subproviders/src/subproviders/mnemonic_wallet.ts deleted file mode 100644 index 140e3d515..000000000 --- a/packages/subproviders/src/subproviders/mnemonic_wallet.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { assert } from '@0x/assert'; -import { EIP712TypedData } from '@0x/types'; -import { addressUtils } from '@0x/utils'; -import * as bip39 from 'bip39'; -import HDNode = require('hdkey'); -import * as _ from 'lodash'; - -import { DerivedHDKeyInfo, MnemonicWalletSubproviderConfigs, PartialTxParams, WalletSubproviderErrors } from '../types'; -import { walletUtils } from '../utils/wallet_utils'; - -import { BaseWalletSubprovider } from './base_wallet_subprovider'; -import { PrivateKeyWalletSubprovider } from './private_key_wallet'; - -const DEFAULT_BASE_DERIVATION_PATH = `44'/60'/0'/0`; -const DEFAULT_NUM_ADDRESSES_TO_FETCH = 10; -const DEFAULT_ADDRESS_SEARCH_LIMIT = 1000; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and handles - * all requests with accounts derived from the supplied mnemonic. - */ -export class MnemonicWalletSubprovider extends BaseWalletSubprovider { - private readonly _addressSearchLimit: number; - private _baseDerivationPath: string; - private _derivedKeyInfo: DerivedHDKeyInfo; - private readonly _mnemonic: string; - - /** - * Instantiates a MnemonicWalletSubprovider. Defaults to baseDerivationPath set to `44'/60'/0'/0`. - * This is the default in TestRPC/Ganache, it can be overridden if desired. - * @param config Configuration for the mnemonic wallet, must contain the mnemonic - * @return MnemonicWalletSubprovider instance - */ - constructor(config: MnemonicWalletSubproviderConfigs) { - assert.isString('mnemonic', config.mnemonic); - const baseDerivationPath = config.baseDerivationPath || DEFAULT_BASE_DERIVATION_PATH; - assert.isString('baseDerivationPath', baseDerivationPath); - const addressSearchLimit = config.addressSearchLimit || DEFAULT_ADDRESS_SEARCH_LIMIT; - assert.isNumber('addressSearchLimit', addressSearchLimit); - super(); - - this._mnemonic = config.mnemonic; - this._baseDerivationPath = baseDerivationPath; - this._addressSearchLimit = addressSearchLimit; - this._derivedKeyInfo = this._initialDerivedKeyInfo(this._baseDerivationPath); - } - /** - * Retrieve the set derivation path - * @returns derivation path - */ - public getPath(): string { - return this._baseDerivationPath; - } - /** - * Set a desired derivation path when computing the available user addresses - * @param baseDerivationPath The desired derivation path (e.g `44'/60'/0'`) - */ - public setPath(baseDerivationPath: string): void { - this._baseDerivationPath = baseDerivationPath; - this._derivedKeyInfo = this._initialDerivedKeyInfo(this._baseDerivationPath); - } - /** - * Retrieve the accounts associated with the mnemonic. - * This method is implicitly called when issuing a `eth_accounts` JSON RPC request - * via your providerEngine instance. - * @param numberOfAccounts Number of accounts to retrieve (default: 10) - * @return An array of accounts - */ - public async getAccountsAsync(numberOfAccounts: number = DEFAULT_NUM_ADDRESSES_TO_FETCH): Promise<string[]> { - const derivedKeys = walletUtils.calculateDerivedHDKeyInfos(this._derivedKeyInfo, numberOfAccounts); - const accounts = _.map(derivedKeys, k => k.address); - return accounts; - } - - /** - * Signs a transaction with the account specificed by the `from` field in txParams. - * If you've added this Subprovider to your app's provider, you can simply send - * an `eth_sendTransaction` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param txParams Parameters of the transaction to sign - * @return Signed transaction hex string - */ - public async signTransactionAsync(txParams: PartialTxParams): Promise<string> { - if (_.isUndefined(txParams.from) || !addressUtils.isAddress(txParams.from)) { - throw new Error(WalletSubproviderErrors.FromAddressMissingOrInvalid); - } - const privateKeyWallet = this._privateKeyWalletForAddress(txParams.from); - const signedTx = privateKeyWallet.signTransactionAsync(txParams); - return signedTx; - } - /** - * Sign a personal Ethereum signed message. The signing account will be the account - * associated with the provided address. If you've added the MnemonicWalletSubprovider to - * your app's provider, you can simply send an `eth_sign` or `personal_sign` JSON RPC request, - * and this method will be called auto-magically. If you are not using this via a ProviderEngine - * instance, you can call it directly. - * @param data Hex string message to sign - * @param address Address of the account to sign with - * @return Signature hex string (order: rsv) - */ - public async signPersonalMessageAsync(data: string, address: string): Promise<string> { - if (_.isUndefined(data)) { - throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage); - } - assert.isHexString('data', data); - assert.isETHAddressHex('address', address); - const privateKeyWallet = this._privateKeyWalletForAddress(address); - const sig = await privateKeyWallet.signPersonalMessageAsync(data, address); - return sig; - } - /** - * Sign an EIP712 Typed Data message. The signing account will be the account - * associated with the provided address. If you've added this MnemonicWalletSubprovider to - * your app's provider, you can simply send an `eth_signTypedData` JSON RPC request, and - * this method will be called auto-magically. If you are not using this via a ProviderEngine - * instance, you can call it directly. - * @param address Address of the account to sign with - * @param data the typed data object - * @return Signature hex string (order: rsv) - */ - public async signTypedDataAsync(address: string, typedData: EIP712TypedData): Promise<string> { - if (_.isUndefined(typedData)) { - throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage); - } - assert.isETHAddressHex('address', address); - const privateKeyWallet = this._privateKeyWalletForAddress(address); - const sig = await privateKeyWallet.signTypedDataAsync(address, typedData); - return sig; - } - private _privateKeyWalletForAddress(address: string): PrivateKeyWalletSubprovider { - const derivedKeyInfo = this._findDerivedKeyInfoForAddress(address); - const privateKeyHex = derivedKeyInfo.hdKey.privateKey.toString('hex'); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKeyHex); - return privateKeyWallet; - } - private _findDerivedKeyInfoForAddress(address: string): DerivedHDKeyInfo { - const matchedDerivedKeyInfo = walletUtils.findDerivedKeyInfoForAddressIfExists( - address, - this._derivedKeyInfo, - this._addressSearchLimit, - ); - if (_.isUndefined(matchedDerivedKeyInfo)) { - throw new Error(`${WalletSubproviderErrors.AddressNotFound}: ${address}`); - } - return matchedDerivedKeyInfo; - } - private _initialDerivedKeyInfo(baseDerivationPath: string): DerivedHDKeyInfo { - const seed = bip39.mnemonicToSeed(this._mnemonic); - const hdKey = HDNode.fromMasterSeed(seed); - // Walk down to base derivation level (i.e m/44'/60'/0') and create an initial key at that level - // all children will then be walked relative (i.e m/0) - const parentKeyDerivationPath = `m/${baseDerivationPath}`; - const parentHDKeyAtDerivationPath = hdKey.derive(parentKeyDerivationPath); - const address = walletUtils.addressOfHDKey(parentHDKeyAtDerivationPath); - const derivedKeyInfo = { - address, - baseDerivationPath, - derivationPath: parentKeyDerivationPath, - hdKey: parentHDKeyAtDerivationPath, - }; - return derivedKeyInfo; - } -} diff --git a/packages/subproviders/src/subproviders/nonce_tracker.ts b/packages/subproviders/src/subproviders/nonce_tracker.ts deleted file mode 100644 index eea722aee..000000000 --- a/packages/subproviders/src/subproviders/nonce_tracker.ts +++ /dev/null @@ -1,110 +0,0 @@ -import * as _ from 'lodash'; - -import { BlockParamLiteral, JSONRPCRequestPayload } from 'ethereum-types'; -import EthereumTx = require('ethereumjs-tx'); -import ethUtil = require('ethereumjs-util'); -import providerEngineUtils = require('web3-provider-engine/util/rpc-cache-utils'); - -import { Callback, ErrorCallback, NextCallback, NonceSubproviderErrors } from '../types'; - -import { Subprovider } from './subprovider'; - -const NONCE_TOO_LOW_ERROR_MESSAGE = 'Transaction nonce is too low'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * It is heavily inspired by the [NonceSubprovider](https://github.com/MetaMask/provider-engine/blob/master/subproviders/nonce-tracker.js). - * We added the additional feature of clearing the cached nonce value when a `nonce value too low` error occurs. - */ -export class NonceTrackerSubprovider extends Subprovider { - private readonly _nonceCache: { [address: string]: string } = {}; - private static _reconstructTransaction(payload: JSONRPCRequestPayload): EthereumTx { - const raw = payload.params[0]; - if (_.isUndefined(raw)) { - throw new Error(NonceSubproviderErrors.EmptyParametersFound); - } - const rawData = ethUtil.toBuffer(raw); - const transaction = new EthereumTx(rawData); - return transaction; - } - private static _determineAddress(payload: JSONRPCRequestPayload): string { - let address: string; - switch (payload.method) { - case 'eth_getTransactionCount': - address = payload.params[0].toLowerCase(); - return address; - case 'eth_sendRawTransaction': - const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); - const addressRaw = transaction - .getSenderAddress() - .toString('hex') - .toLowerCase(); - address = `0x${addressRaw}`; - return address; - default: - throw new Error(NonceSubproviderErrors.CannotDetermineAddressFromPayload); - } - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, next: NextCallback, end: ErrorCallback): Promise<void> { - switch (payload.method) { - case 'eth_getTransactionCount': - const requestDefaultBlock = providerEngineUtils.blockTagForPayload(payload); - if (requestDefaultBlock === BlockParamLiteral.Pending) { - const address = NonceTrackerSubprovider._determineAddress(payload); - const cachedResult = this._nonceCache[address]; - if (!_.isUndefined(cachedResult)) { - return end(null, cachedResult); - } else { - return next((requestError: Error | null, requestResult: any, cb: Callback) => { - if (_.isNull(requestError)) { - this._nonceCache[address] = requestResult as string; - } - cb(); - }); - } - } else { - return next(); - } - case 'eth_sendRawTransaction': - return next((sendTransactionError: Error | null, _txResult: any, cb: Callback) => { - if (_.isNull(sendTransactionError)) { - this._handleSuccessfulTransaction(payload); - } else { - this._handleSendTransactionError(payload, sendTransactionError); - } - cb(); - }); - default: - return next(); - } - } - private _handleSuccessfulTransaction(payload: JSONRPCRequestPayload): void { - const address = NonceTrackerSubprovider._determineAddress(payload); - const transaction = NonceTrackerSubprovider._reconstructTransaction(payload); - // Increment the nonce from the previous successfully submitted transaction - let nonce = ethUtil.bufferToInt(transaction.nonce); - nonce++; - const hexBase = 16; - let nextHexNonce = nonce.toString(hexBase); - if (nextHexNonce.length % 2) { - nextHexNonce = `0${nextHexNonce}`; - } - const nextPrefixedHexNonce = `0x${nextHexNonce}`; - this._nonceCache[address] = nextPrefixedHexNonce; - } - private _handleSendTransactionError(payload: JSONRPCRequestPayload, err: Error): void { - const address = NonceTrackerSubprovider._determineAddress(payload); - if (this._nonceCache[address] && _.includes(err.message, NONCE_TOO_LOW_ERROR_MESSAGE)) { - delete this._nonceCache[address]; - } - } -} diff --git a/packages/subproviders/src/subproviders/private_key_wallet.ts b/packages/subproviders/src/subproviders/private_key_wallet.ts deleted file mode 100644 index dca7e6810..000000000 --- a/packages/subproviders/src/subproviders/private_key_wallet.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { assert } from '@0x/assert'; -import { EIP712TypedData } from '@0x/types'; -import { signTypedDataUtils } from '@0x/utils'; -import EthereumTx = require('ethereumjs-tx'); -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { PartialTxParams, WalletSubproviderErrors } from '../types'; - -import { BaseWalletSubprovider } from './base_wallet_subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and handles - * all requests with the supplied Ethereum private key. - */ -export class PrivateKeyWalletSubprovider extends BaseWalletSubprovider { - private readonly _address: string; - private readonly _privateKeyBuffer: Buffer; - /** - * Instantiates a PrivateKeyWalletSubprovider. - * @param privateKey The corresponding private key to an Ethereum address - * @return PrivateKeyWalletSubprovider instance - */ - constructor(privateKey: string) { - assert.isString('privateKey', privateKey); - super(); - this._privateKeyBuffer = Buffer.from(privateKey, 'hex'); - this._address = `0x${ethUtil.privateToAddress(this._privateKeyBuffer).toString('hex')}`; - } - /** - * Retrieve the account associated with the supplied private key. - * This method is implicitly called when issuing a `eth_accounts` JSON RPC request - * via your providerEngine instance. - * @return An array of accounts - */ - public async getAccountsAsync(): Promise<string[]> { - return [this._address]; - } - /** - * Sign a transaction with the private key. If you've added this Subprovider to your - * app's provider, you can simply send an `eth_sendTransaction` JSON RPC request, and - * this method will be called auto-magically. If you are not using this via a ProviderEngine - * instance, you can call it directly. - * @param txParams Parameters of the transaction to sign - * @return Signed transaction hex string - */ - public async signTransactionAsync(txParams: PartialTxParams): Promise<string> { - PrivateKeyWalletSubprovider._validateTxParams(txParams); - if (!_.isUndefined(txParams.from) && txParams.from !== this._address) { - throw new Error( - `Requested to sign transaction with address: ${txParams.from}, instantiated with address: ${ - this._address - }`, - ); - } - const tx = new EthereumTx(txParams); - tx.sign(this._privateKeyBuffer); - const rawTx = `0x${tx.serialize().toString('hex')}`; - return rawTx; - } - /** - * Sign a personal Ethereum signed message. The signing address will be calculated from the private key. - * The address must be provided it must match the address calculated from the private key. - * If you've added this Subprovider to your app's provider, you can simply send an `eth_sign` - * or `personal_sign` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param data Hex string message to sign - * @param address Address of the account to sign with - * @return Signature hex string (order: rsv) - */ - public async signPersonalMessageAsync(data: string, address: string): Promise<string> { - if (_.isUndefined(data)) { - throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage); - } - assert.isHexString('data', data); - assert.isETHAddressHex('address', address); - if (address !== this._address) { - throw new Error( - `Requested to sign message with address: ${address}, instantiated with address: ${this._address}`, - ); - } - const dataBuff = ethUtil.toBuffer(data); - const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); - const sig = ethUtil.ecsign(msgHashBuff, this._privateKeyBuffer); - const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s); - return rpcSig; - } - /** - * Sign an EIP712 Typed Data message. The signing address will be calculated from the private key. - * The address must be provided it must match the address calculated from the private key. - * If you've added this Subprovider to your app's provider, you can simply send an `eth_signTypedData` - * JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param address Address of the account to sign with - * @param data the typed data object - * @return Signature hex string (order: rsv) - */ - public async signTypedDataAsync(address: string, typedData: EIP712TypedData): Promise<string> { - if (_.isUndefined(typedData)) { - throw new Error(WalletSubproviderErrors.DataMissingForSignTypedData); - } - assert.isETHAddressHex('address', address); - if (address !== this._address) { - throw new Error( - `Requested to sign message with address: ${address}, instantiated with address: ${this._address}`, - ); - } - const dataBuff = signTypedDataUtils.generateTypedDataHash(typedData); - const sig = ethUtil.ecsign(dataBuff, this._privateKeyBuffer); - const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s); - return rpcSig; - } -} diff --git a/packages/subproviders/src/subproviders/redundant_subprovider.ts b/packages/subproviders/src/subproviders/redundant_subprovider.ts deleted file mode 100644 index 58312f203..000000000 --- a/packages/subproviders/src/subproviders/redundant_subprovider.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { promisify } from '@0x/utils'; -import { JSONRPCRequestPayload } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { Callback } from '../types'; - -import { Subprovider } from './subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * It attempts to handle each JSON RPC request by sequentially attempting to receive a valid response from one of a - * set of JSON RPC endpoints. - */ -export class RedundantSubprovider extends Subprovider { - private readonly _subproviders: Subprovider[]; - private static async _firstSuccessAsync( - subproviders: Subprovider[], - payload: JSONRPCRequestPayload, - next: Callback, - ): Promise<any> { - let lastErr: Error | undefined; - for (const subprovider of subproviders) { - try { - const data = await promisify(subprovider.handleRequest.bind(subprovider))(payload, next); - return data; - } catch (err) { - lastErr = err; - continue; - } - } - if (!_.isUndefined(lastErr)) { - throw lastErr; - } - } - /** - * Instantiates a new RedundantSubprovider - * @param subproviders Subproviders to attempt the request with - */ - constructor(subproviders: Subprovider[]) { - super(); - this._subproviders = subproviders; - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:async-suffix - public async handleRequest( - payload: JSONRPCRequestPayload, - next: Callback, - end: (err: Error | null, data?: any) => void, - ): Promise<void> { - const subprovidersCopy = this._subproviders.slice(); - try { - const data = await RedundantSubprovider._firstSuccessAsync(subprovidersCopy, payload, next); - end(null, data); - } catch (err) { - end(err); - } - } -} diff --git a/packages/subproviders/src/subproviders/rpc_subprovider.ts b/packages/subproviders/src/subproviders/rpc_subprovider.ts deleted file mode 100644 index 437518e12..000000000 --- a/packages/subproviders/src/subproviders/rpc_subprovider.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { assert } from '@0x/assert'; -import { StatusCodes } from '@0x/types'; -import { fetchAsync } from '@0x/utils'; -import { JSONRPCRequestPayload } from 'ethereum-types'; -import JsonRpcError = require('json-rpc-error'); - -import { Callback, ErrorCallback } from '../types'; - -import { Subprovider } from './subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * It forwards on JSON RPC requests to the supplied `rpcUrl` endpoint - */ -export class RPCSubprovider extends Subprovider { - private readonly _rpcUrl: string; - private readonly _requestTimeoutMs: number; - /** - * @param rpcUrl URL to the backing Ethereum node to which JSON RPC requests should be sent - * @param requestTimeoutMs Amount of miliseconds to wait before timing out the JSON RPC request - */ - constructor(rpcUrl: string, requestTimeoutMs: number = 20000) { - super(); - assert.isString('rpcUrl', rpcUrl); - assert.isNumber('requestTimeoutMs', requestTimeoutMs); - this._rpcUrl = rpcUrl; - this._requestTimeoutMs = requestTimeoutMs; - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param _next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:prefer-function-over-method async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, _next: Callback, end: ErrorCallback): Promise<void> { - const finalPayload = Subprovider._createFinalPayload(payload); - const headers = new Headers({ - Accept: 'application/json', - 'Content-Type': 'application/json', - }); - - let response; - try { - response = await fetchAsync( - this._rpcUrl, - { - method: 'POST', - headers, - body: JSON.stringify(finalPayload), - }, - this._requestTimeoutMs, - ); - } catch (err) { - end(new JsonRpcError.InternalError(err)); - return; - } - - const text = await response.text(); - if (!response.ok) { - const statusCode = response.status; - switch (statusCode) { - case StatusCodes.MethodNotAllowed: - end(new JsonRpcError.MethodNotFound()); - return; - case StatusCodes.GatewayTimeout: - const errMsg = - 'Gateway timeout. The request took too long to process. This can happen when querying logs over too wide a block range.'; - const err = new Error(errMsg); - end(new JsonRpcError.InternalError(err)); - return; - default: - end(new JsonRpcError.InternalError(text)); - return; - } - } - - let data; - try { - data = JSON.parse(text); - } catch (err) { - end(new JsonRpcError.InternalError(err)); - return; - } - - if (data.error) { - end(data.error); - return; - } - end(null, data.result); - } -} diff --git a/packages/subproviders/src/subproviders/signer.ts b/packages/subproviders/src/subproviders/signer.ts deleted file mode 100644 index 9bd5cbdf1..000000000 --- a/packages/subproviders/src/subproviders/signer.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { marshaller, Web3Wrapper } from '@0x/web3-wrapper'; -import { JSONRPCRequestPayload, Provider } from 'ethereum-types'; - -import { Callback, ErrorCallback } from '../types'; - -import { Subprovider } from './subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) - * subprovider interface. It forwards JSON RPC requests involving the domain of a signer (getAccounts, - * sendTransaction, signMessage etc...) to the provider instance supplied at instantiation. All other requests - * are passed onwards for subsequent subproviders to handle. - */ -export class SignerSubprovider extends Subprovider { - private readonly _web3Wrapper: Web3Wrapper; - /** - * Instantiates a new SignerSubprovider. - * @param provider Web3 provider that should handle all user account related requests - */ - constructor(provider: Provider) { - super(); - this._web3Wrapper = new Web3Wrapper(provider); - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:prefer-function-over-method async-suffix - public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback): Promise<void> { - let message; - let address; - switch (payload.method) { - case 'web3_clientVersion': - try { - const nodeVersion = await this._web3Wrapper.getNodeVersionAsync(); - end(null, nodeVersion); - } catch (err) { - end(err); - } - return; - case 'eth_accounts': - try { - const accounts = await this._web3Wrapper.getAvailableAddressesAsync(); - end(null, accounts); - } catch (err) { - end(err); - } - return; - case 'eth_sendTransaction': - const [txParams] = payload.params; - try { - const txData = marshaller.unmarshalTxData(txParams); - const txHash = await this._web3Wrapper.sendTransactionAsync(txData); - end(null, txHash); - } catch (err) { - end(err); - } - return; - case 'eth_sign': - [address, message] = payload.params; - try { - const signature = await this._web3Wrapper.signMessageAsync(address, message); - end(null, signature); - } catch (err) { - end(err); - } - return; - case 'eth_signTypedData': - [address, message] = payload.params; - try { - const signature = await this._web3Wrapper.signTypedDataAsync(address, message); - end(null, signature); - } catch (err) { - end(err); - } - return; - default: - next(); - return; - } - } -} diff --git a/packages/subproviders/src/subproviders/subprovider.ts b/packages/subproviders/src/subproviders/subprovider.ts deleted file mode 100644 index cd6780e0c..000000000 --- a/packages/subproviders/src/subproviders/subprovider.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { promisify } from '@0x/utils'; -import { JSONRPCRequestPayload, JSONRPCResponsePayload, Provider } from 'ethereum-types'; - -import { Callback, ErrorCallback, JSONRPCRequestPayloadWithMethod } from '../types'; -/** - * A altered version of the base class Subprovider found in [web3-provider-engine](https://github.com/MetaMask/provider-engine). - * This one has an async/await `emitPayloadAsync` and also defined types. - */ -export abstract class Subprovider { - // tslint:disable-next-line:underscore-private-and-protected - private engine!: Provider; - protected static _createFinalPayload( - payload: Partial<JSONRPCRequestPayloadWithMethod>, - ): Partial<JSONRPCRequestPayloadWithMethod> { - const finalPayload = { - // defaults - id: Subprovider._getRandomId(), - jsonrpc: '2.0', - params: [], - ...payload, - }; - return finalPayload; - } - // Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js - private static _getRandomId(): number { - const extraDigits = 3; - const baseTen = 10; - // 13 time digits - const datePart = new Date().getTime() * Math.pow(baseTen, extraDigits); - // 3 random digits - const extraPart = Math.floor(Math.random() * Math.pow(baseTen, extraDigits)); - // 16 digits - return datePart + extraPart; - } - /** - * @param payload JSON RPC request payload - * @param next A callback to pass the request to the next subprovider in the stack - * @param end A callback called once the subprovider is done handling the request - */ - // tslint:disable-next-line:async-suffix - public abstract async handleRequest( - payload: JSONRPCRequestPayload, - next: Callback, - end: ErrorCallback, - ): Promise<void>; - - /** - * Emits a JSON RPC payload that will then be handled by the ProviderEngine instance - * this subprovider is a part of. The payload will cascade down the subprovider middleware - * stack until finding the responsible entity for handling the request. - * @param payload JSON RPC payload - * @returns JSON RPC response payload - */ - public async emitPayloadAsync(payload: Partial<JSONRPCRequestPayloadWithMethod>): Promise<JSONRPCResponsePayload> { - const finalPayload = Subprovider._createFinalPayload(payload); - // Promisify does the binding internally and `this` is supplied as a second argument - // tslint:disable-next-line:no-unbound-method - const response = await promisify<JSONRPCResponsePayload>(this.engine.sendAsync, this.engine)(finalPayload); - return response; - } - /** - * Set's the subprovider's engine to the ProviderEngine it is added to. - * This is only called within the ProviderEngine source code, do not call - * directly. - * @param engine The ProviderEngine this subprovider is added to - */ - public setEngine(engine: Provider): void { - this.engine = engine; - } -} diff --git a/packages/subproviders/src/types.ts b/packages/subproviders/src/types.ts deleted file mode 100644 index ed3aea176..000000000 --- a/packages/subproviders/src/types.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { ECSignature } from '@0x/types'; -import { JSONRPCRequestPayload } from 'ethereum-types'; -import HDNode = require('hdkey'); - -export interface LedgerCommunicationClient { - close: () => Promise<void>; -} - -/** - * Elliptic Curve signature - * The LedgerEthereumClient sends Ethereum-specific requests to the Ledger Nano S - * It uses an internal LedgerCommunicationClient to relay these requests. Currently - * NodeJs and Browser communication are supported. - */ -export interface LedgerEthereumClient { - // shouldGetChainCode is defined as `true` instead of `boolean` because other types rely on the assumption - // that we get back the chain code and we don't have dependent types to express it properly - getAddress: ( - derivationPath: string, - askForDeviceConfirmation: boolean, - shouldGetChainCode: true, - ) => Promise<LedgerGetAddressResult>; - signTransaction: (derivationPath: string, rawTxHex: string) => Promise<ECSignatureString>; - signPersonalMessage: (derivationPath: string, messageHex: string) => Promise<ECSignature>; - transport: LedgerCommunicationClient; -} - -export interface ECSignatureString { - v: string; - r: string; - s: string; -} - -export type LedgerEthereumClientFactoryAsync = () => Promise<LedgerEthereumClient>; - -/** - * networkId: The ethereum networkId to set as the chainId from EIP155 - * ledgerConnectionType: Environment in which you wish to connect to Ledger (nodejs or browser) - * derivationPath: Initial derivation path to use e.g 44'/60'/0' - * accountFetchingConfigs: configs related to fetching accounts from a Ledger - */ -export interface LedgerSubproviderConfigs { - networkId: number; - ledgerEthereumClientFactoryAsync: LedgerEthereumClientFactoryAsync; - baseDerivationPath?: string; - accountFetchingConfigs?: AccountFetchingConfigs; -} - -/** - * addressSearchLimit: The maximum number of addresses to search through, defaults to 1000 - * numAddressesToReturn: Number of addresses to return from 'eth_accounts' call - * shouldAskForOnDeviceConfirmation: Whether you wish to prompt the user on their Ledger - * before fetching their addresses - */ -export interface AccountFetchingConfigs { - addressSearchLimit?: number; - numAddressesToReturn?: number; - shouldAskForOnDeviceConfirmation?: boolean; -} - -/** - * mnemonic: The string mnemonic seed - * addressSearchLimit: The maximum number of addresses to search through, defaults to 1000 - * baseDerivationPath: The base derivation path (e.g 44'/60'/0'/0) - */ -export interface MnemonicWalletSubproviderConfigs { - mnemonic: string; - addressSearchLimit?: number; - baseDerivationPath?: string; -} - -export interface SignatureData { - hash: string; - r: string; - s: string; - v: number; -} - -export interface LedgerGetAddressResult { - address: string; - publicKey: string; - chainCode: string; -} - -export interface PartialTxParams { - nonce: string; - gasPrice?: string; - gas: string; - to: string; - from: string; - value?: string; - data?: string; - chainId: number; // EIP 155 chainId - mainnet: 1, ropsten: 3 -} - -export type DoneCallback = (err?: Error) => void; - -export interface LedgerCommunication { - close_async: () => Promise<void>; -} - -export interface ResponseWithTxParams { - raw: string; - tx: PartialTxParams; -} - -export enum WalletSubproviderErrors { - AddressNotFound = 'ADDRESS_NOT_FOUND', - DataMissingForSignPersonalMessage = 'DATA_MISSING_FOR_SIGN_PERSONAL_MESSAGE', - DataMissingForSignTypedData = 'DATA_MISSING_FOR_SIGN_TYPED_DATA', - SenderInvalidOrNotSupplied = 'SENDER_INVALID_OR_NOT_SUPPLIED', - FromAddressMissingOrInvalid = 'FROM_ADDRESS_MISSING_OR_INVALID', - MethodNotSupported = 'METHOD_NOT_SUPPORTED', -} -export enum LedgerSubproviderErrors { - TooOldLedgerFirmware = 'TOO_OLD_LEDGER_FIRMWARE', - MultipleOpenConnectionsDisallowed = 'MULTIPLE_OPEN_CONNECTIONS_DISALLOWED', -} - -export enum NonceSubproviderErrors { - EmptyParametersFound = 'EMPTY_PARAMETERS_FOUND', - CannotDetermineAddressFromPayload = 'CANNOT_DETERMINE_ADDRESS_FROM_PAYLOAD', -} -export interface DerivedHDKeyInfo { - address: string; - baseDerivationPath: string; - derivationPath: string; - hdKey: HDNode; -} - -export type ErrorCallback = (err: Error | null, data?: any) => void; -export type Callback = () => void; -export type OnNextCompleted = (err: Error | null, result: any, cb: Callback) => void; -export type NextCallback = (callback?: OnNextCompleted) => void; - -export interface JSONRPCRequestPayloadWithMethod extends JSONRPCRequestPayload { - method: string; -} diff --git a/packages/subproviders/src/utils/subprovider_utils.ts b/packages/subproviders/src/utils/subprovider_utils.ts deleted file mode 100644 index beda408ab..000000000 --- a/packages/subproviders/src/utils/subprovider_utils.ts +++ /dev/null @@ -1,15 +0,0 @@ -import Web3ProviderEngine = require('web3-provider-engine'); - -import { Subprovider } from '../subproviders/subprovider'; - -/** - * Prepends a subprovider to a provider - * @param provider Given provider - * @param subprovider Subprovider to prepend - */ -export function prependSubprovider(provider: Web3ProviderEngine, subprovider: Subprovider): void { - subprovider.setEngine(provider); - // HACK: We use implementation details of provider engine here - // https://github.com/MetaMask/provider-engine/blob/master/index.js#L68 - (provider as any)._providers = [subprovider, ...(provider as any)._providers]; -} diff --git a/packages/subproviders/src/utils/wallet_utils.ts b/packages/subproviders/src/utils/wallet_utils.ts deleted file mode 100644 index 7027ca8a0..000000000 --- a/packages/subproviders/src/utils/wallet_utils.ts +++ /dev/null @@ -1,79 +0,0 @@ -import ethUtil = require('ethereumjs-util'); -import HDNode = require('hdkey'); - -import { DerivedHDKeyInfo } from '../types'; - -const DEFAULT_ADDRESS_SEARCH_LIMIT = 1000; - -class DerivedHDKeyInfoIterator implements IterableIterator<DerivedHDKeyInfo> { - private readonly _parentDerivedKeyInfo: DerivedHDKeyInfo; - private readonly _searchLimit: number; - private _index: number; - - constructor(initialDerivedKey: DerivedHDKeyInfo, searchLimit: number = DEFAULT_ADDRESS_SEARCH_LIMIT) { - this._searchLimit = searchLimit; - this._parentDerivedKeyInfo = initialDerivedKey; - this._index = 0; - } - - public next(): IteratorResult<DerivedHDKeyInfo> { - const baseDerivationPath = this._parentDerivedKeyInfo.baseDerivationPath; - const derivationIndex = this._index; - const fullDerivationPath = `m/${baseDerivationPath}/${derivationIndex}`; - const path = `m/${derivationIndex}`; - const hdKey = this._parentDerivedKeyInfo.hdKey.derive(path); - const address = walletUtils.addressOfHDKey(hdKey); - const derivedKey: DerivedHDKeyInfo = { - address, - hdKey, - baseDerivationPath, - derivationPath: fullDerivationPath, - }; - const isDone = this._index === this._searchLimit; - this._index++; - return { - done: isDone, - value: derivedKey, - }; - } - - public [Symbol.iterator](): IterableIterator<DerivedHDKeyInfo> { - return this; - } -} - -export const walletUtils = { - calculateDerivedHDKeyInfos(parentDerivedKeyInfo: DerivedHDKeyInfo, numberOfKeys: number): DerivedHDKeyInfo[] { - const derivedKeys: DerivedHDKeyInfo[] = []; - const derivedKeyIterator = new DerivedHDKeyInfoIterator(parentDerivedKeyInfo, numberOfKeys); - for (const key of derivedKeyIterator) { - derivedKeys.push(key); - } - return derivedKeys; - }, - findDerivedKeyInfoForAddressIfExists( - address: string, - parentDerivedKeyInfo: DerivedHDKeyInfo, - searchLimit: number, - ): DerivedHDKeyInfo | undefined { - const lowercaseAddress = address.toLowerCase(); - let matchedKey: DerivedHDKeyInfo | undefined; - const derivedKeyIterator = new DerivedHDKeyInfoIterator(parentDerivedKeyInfo, searchLimit); - for (const key of derivedKeyIterator) { - if (key.address === lowercaseAddress) { - matchedKey = key; - break; - } - } - return matchedKey; - }, - addressOfHDKey(hdKey: HDNode): string { - const shouldSanitizePublicKey = true; - const derivedPublicKey = hdKey.publicKey; - const ethereumAddressUnprefixed = ethUtil - .publicToAddress(derivedPublicKey, shouldSanitizePublicKey) - .toString('hex'); - const address = ethUtil.addHexPrefix(ethereumAddressUnprefixed).toLowerCase(); - return address; - }, -}; diff --git a/packages/subproviders/test/chai_setup.ts b/packages/subproviders/test/chai_setup.ts deleted file mode 100644 index 6c24dc222..000000000 --- a/packages/subproviders/test/chai_setup.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as chai from 'chai'; -import chaiAsPromised = require('chai-as-promised'); -import * as dirtyChai from 'dirty-chai'; - -export const chaiSetup = { - configure(): void { - chai.config.includeStack = true; - chai.use(dirtyChai); - chai.use(chaiAsPromised); - }, -}; diff --git a/packages/subproviders/test/integration/ledger_subprovider_test.ts b/packages/subproviders/test/integration/ledger_subprovider_test.ts deleted file mode 100644 index b072e611b..000000000 --- a/packages/subproviders/test/integration/ledger_subprovider_test.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { DoneCallback } from '@0x/types'; -import { promisify } from '@0x/utils'; -import Eth from '@ledgerhq/hw-app-eth'; -// HACK: This dependency is optional and tslint skips optional dependencies -// tslint:disable-next-line:no-implicit-dependencies -import TransportNodeHid from '@ledgerhq/hw-transport-node-hid'; -import * as chai from 'chai'; -import { JSONRPCResponsePayload } from 'ethereum-types'; -import * as ethUtils from 'ethereumjs-util'; - -import { LedgerSubprovider, RPCSubprovider, Web3ProviderEngine } from '../../src'; -import { LedgerEthereumClient } from '../../src/types'; -import { chaiSetup } from '../chai_setup'; -import { fixtureData } from '../utils/fixture_data'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -chaiSetup.configure(); -const expect = chai.expect; -const DEFAULT_NUM_ACCOUNTS = 10; -const EXPECTED_SIGNATURE_LENGTH = 132; - -async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumClient> { - const ledgerConnection = await TransportNodeHid.create(); - const ledgerEthClient = new Eth(ledgerConnection); - return ledgerEthClient; -} - -describe('LedgerSubprovider', () => { - let ledgerSubprovider: LedgerSubprovider; - const networkId: number = fixtureData.NETWORK_ID; - before(async () => { - ledgerSubprovider = new LedgerSubprovider({ - networkId, - ledgerEthereumClientFactoryAsync: ledgerEthereumNodeJsClientFactoryAsync, - baseDerivationPath: fixtureData.TESTRPC_BASE_DERIVATION_PATH, - }); - }); - describe('direct method calls', () => { - it('returns default number of accounts', async () => { - const accounts = await ledgerSubprovider.getAccountsAsync(); - expect(accounts[0]).to.not.be.an('undefined'); - expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - }); - it('returns the expected accounts from a ledger set up with the test mnemonic', async () => { - const accounts = await ledgerSubprovider.getAccountsAsync(); - expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(accounts[1]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_1); - }); - it('returns requested number of accounts', async () => { - const numberOfAccounts = 20; - const accounts = await ledgerSubprovider.getAccountsAsync(numberOfAccounts); - expect(accounts[0]).to.not.be.an('undefined'); - expect(accounts.length).to.be.equal(numberOfAccounts); - }); - it('signs a personal message', async () => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync( - data, - fixtureData.TEST_RPC_ACCOUNT_0, - ); - expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - }); - it('signs a personal message with second address', async () => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync( - data, - fixtureData.TEST_RPC_ACCOUNT_1, - ); - expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_ACCOUNT_1_SIGNED_RESULT); - }); - it('signs a transaction', async () => { - const txHex = await ledgerSubprovider.signTransactionAsync(fixtureData.TX_DATA); - expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - }); - it('signs a transaction with the second address', async () => { - const txData = { ...fixtureData.TX_DATA, from: fixtureData.TEST_RPC_ACCOUNT_1 }; - const txHex = await ledgerSubprovider.signTransactionAsync(txData); - expect(txHex).to.be.equal(fixtureData.TX_DATA_ACCOUNT_1_SIGNED_RESULT); - }); - }); - describe('calls through a provider', () => { - let defaultProvider: Web3ProviderEngine; - let ledgerProvider: Web3ProviderEngine; - before(() => { - ledgerProvider = new Web3ProviderEngine(); - ledgerProvider.addProvider(ledgerSubprovider); - const httpProvider = new RPCSubprovider('http://localhost:8545'); - ledgerProvider.addProvider(httpProvider); - ledgerProvider.start(); - - defaultProvider = new Web3ProviderEngine(); - defaultProvider.addProvider(httpProvider); - defaultProvider.start(); - }); - it('returns a list of accounts', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - done(); - }); - ledgerProvider.sendAsync(payload, callback); - }); - it('signs a personal message with eth_sign', (done: DoneCallback) => { - (async () => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - const accounts = await ledgerSubprovider.getAccountsAsync(); - const signer = accounts[0]; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [signer, messageHex], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.length).to.be.equal(EXPECTED_SIGNATURE_LENGTH); - expect(response.result.substr(0, 2)).to.be.equal('0x'); - done(); - }); - ledgerProvider.sendAsync(payload, callback); - })().catch(done); - }); - it('signs a personal message with personal_sign', (done: DoneCallback) => { - (async () => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - const accounts = await ledgerSubprovider.getAccountsAsync(); - const signer = accounts[0]; - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex, signer], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.length).to.be.equal(EXPECTED_SIGNATURE_LENGTH); - expect(response.result.substr(0, 2)).to.be.equal('0x'); - done(); - }); - ledgerProvider.sendAsync(payload, callback); - })().catch(done); - }); - it('signs a transaction', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTransaction', - params: [fixtureData.TX_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.raw).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - done(); - }); - ledgerProvider.sendAsync(payload, callback); - }); - it('signs and sends a transaction', (done: DoneCallback) => { - (async () => { - const accounts = await ledgerSubprovider.getAccountsAsync(); - - // Give first account on Ledger sufficient ETH to complete tx send - let tx = { - to: accounts[0], - from: fixtureData.TEST_RPC_ACCOUNT_0, - value: '0x8ac7230489e80000', // 10 ETH - }; - let payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - await promisify(defaultProvider.sendAsync.bind(defaultProvider))(payload); - - // Send transaction from Ledger - tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - from: accounts[0], - value: '0xde0b6b3a7640000', - }; - payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - const result = response.result; - const signedTxLength = 66; - expect(result.length).to.be.equal(signedTxLength); - expect(result.substr(0, 2)).to.be.equal('0x'); - done(); - }); - ledgerProvider.sendAsync(payload, callback); - })().catch(done); - }); - }); -}); diff --git a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts deleted file mode 100644 index 49698ce9e..000000000 --- a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts +++ /dev/null @@ -1,187 +0,0 @@ -import * as chai from 'chai'; -import * as lightwallet from 'eth-lightwallet'; -import { JSONRPCResponsePayload } from 'ethereum-types'; -import * as ethUtils from 'ethereumjs-util'; - -import { EthLightwalletSubprovider, Web3ProviderEngine } from '../../src'; -import { DoneCallback } from '../../src/types'; -import { chaiSetup } from '../chai_setup'; -import { fixtureData } from '../utils/fixture_data'; -import { ganacheSubprovider } from '../utils/ganache_subprovider'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -chaiSetup.configure(); -const expect = chai.expect; - -const DEFAULT_NUM_ACCOUNTS = 10; -const PASSWORD = 'supersecretpassword99'; -const SALT = 'kvODghzs7Ff1uqHyI0P3wI4Hso4w4iWT2e9qmrWz0y4'; - -describe('EthLightwalletSubprovider', () => { - let ethLightwalletSubprovider: EthLightwalletSubprovider; - before(async () => { - const options = { - password: PASSWORD, - seedPhrase: fixtureData.TEST_RPC_MNEMONIC, - salt: SALT, - hdPathString: fixtureData.TESTRPC_BASE_DERIVATION_PATH, - }; - const createVaultAsync = async (vaultOptions: lightwallet.VaultOptions) => { - return new Promise<lightwallet.keystore>(resolve => { - lightwallet.keystore.createVault(vaultOptions, (err: Error, vaultKeystore) => { - if (err) { - throw new Error(`Failed to createVault: ${err}`); - } - resolve(vaultKeystore); - }); - }); - }; - const deriveKeyFromPasswordAsync = async (vaultKeystore: lightwallet.keystore) => { - return new Promise<Uint8Array>(resolve => { - vaultKeystore.keyFromPassword(PASSWORD, (err: Error, passwordDerivedKey: Uint8Array) => { - if (err) { - throw new Error(`Failed to get key from password: ${err}`); - } - resolve(passwordDerivedKey); - }); - }); - }; - const keystore: lightwallet.keystore = await createVaultAsync(options); - const pwDerivedKey: Uint8Array = await deriveKeyFromPasswordAsync(keystore); - - // Generate 10 addresses - keystore.generateNewAddress(pwDerivedKey, DEFAULT_NUM_ACCOUNTS); - - ethLightwalletSubprovider = new EthLightwalletSubprovider(keystore, pwDerivedKey); - }); - describe('direct method calls', () => { - describe('success cases', () => { - it('returns a list of accounts', async () => { - const accounts = await ethLightwalletSubprovider.getAccountsAsync(); - expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(accounts[1]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_1); - expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - }); - it('signs a personal message hash', async () => { - const accounts = await ethLightwalletSubprovider.getAccountsAsync(); - const signingAccount = accounts[0]; - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await ethLightwalletSubprovider.signPersonalMessageAsync(data, signingAccount); - expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - }); - it('signs a transaction', async () => { - const txHex = await ethLightwalletSubprovider.signTransactionAsync(fixtureData.TX_DATA); - expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - }); - it('signs an EIP712 sign typed data message', async () => { - const signature = await ethLightwalletSubprovider.signTypedDataAsync( - fixtureData.TEST_RPC_ACCOUNT_0, - fixtureData.EIP712_TEST_TYPED_DATA, - ); - expect(signature).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - }); - }); - }); - describe('calls through a provider', () => { - let provider: Web3ProviderEngine; - before(() => { - provider = new Web3ProviderEngine(); - provider.addProvider(ethLightwalletSubprovider); - provider.addProvider(ganacheSubprovider); - provider.start(); - }); - describe('success cases', () => { - it('returns a list of accounts', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message hash with eth_sign', (done: DoneCallback) => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const account = fixtureData.TEST_RPC_ACCOUNT_0; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [account, data], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a transaction', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTransaction', - params: [fixtureData.TX_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.raw).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs an EIP712 sign typed data message with eth_signTypedData', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTypedData', - params: [fixtureData.TEST_RPC_ACCOUNT_0, fixtureData.EIP712_TEST_TYPED_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - describe('failure cases', () => { - it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [fixtureData.TEST_RPC_ACCOUNT_0, nonHexMessage], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [nonHexMessage, fixtureData.TEST_RPC_ACCOUNT_0], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - }); -}); diff --git a/packages/subproviders/test/unit/ledger_subprovider_test.ts b/packages/subproviders/test/unit/ledger_subprovider_test.ts deleted file mode 100644 index a1d146dbc..000000000 --- a/packages/subproviders/test/unit/ledger_subprovider_test.ts +++ /dev/null @@ -1,255 +0,0 @@ -import * as chai from 'chai'; -import { JSONRPCResponsePayload } from 'ethereum-types'; -import * as ethUtils from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { LedgerSubprovider, Web3ProviderEngine } from '../../src'; -import { - DoneCallback, - LedgerCommunicationClient, - LedgerSubproviderErrors, - WalletSubproviderErrors, -} from '../../src/types'; -import { chaiSetup } from '../chai_setup'; -import { fixtureData } from '../utils/fixture_data'; -import { ganacheSubprovider } from '../utils/ganache_subprovider'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -chaiSetup.configure(); -const expect = chai.expect; -const FAKE_ADDRESS = '0xb088a3bc93f71b4de97b9de773e9647645983688'; -const DEFAULT_NUM_ACCOUNTS = 10; - -describe('LedgerSubprovider', () => { - const networkId: number = 42; - let ledgerSubprovider: LedgerSubprovider; - before(async () => { - const ledgerEthereumClientFactoryAsync = async () => { - // tslint:disable:no-object-literal-type-assertion - const ledgerEthClient = { - getAddress: async () => { - const publicKey = - '04f428290f4c5ed6a198f71b8205f488141dbb3f0840c923bbfa798ecbee6370986c03b5575d94d506772fb48a6a44e345e4ebd4f028a6f609c44b655d6d3e71a1'; - const chainCode = 'ac055a5537c0c7e9e02d14a197cad6b857836da2a12043b46912a37d959b5ae8'; - const address = '0xBa388BA5e5EEF2c6cE42d831c2B3A28D3c99bdB1'; - return { - publicKey, - address, - chainCode, - }; - }, - signPersonalMessage: async () => { - const ecSignature = { - v: 28, - r: 'a6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae49148', - s: '0652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d0', - }; - return ecSignature; - }, - signTransaction: async (_derivationPath: string, _txHex: string) => { - const ecSignature = { - v: '77', - r: '88a95ef1378487bc82be558e82c8478baf840c545d5b887536bb1da63673a98b', - s: '019f4a4b9a107d1e6752bf7f701e275f28c13791d6e76af895b07373462cefaa', - }; - return ecSignature; - }, - transport: { - close: _.noop.bind(_), - } as LedgerCommunicationClient, - }; - // tslint:enable:no-object-literal-type-assertion - return ledgerEthClient; - }; - ledgerSubprovider = new LedgerSubprovider({ - networkId, - ledgerEthereumClientFactoryAsync, - }); - }); - describe('direct method calls', () => { - describe('success cases', () => { - it('returns default number of accounts', async () => { - const accounts = await ledgerSubprovider.getAccountsAsync(); - expect(accounts[0]).to.be.equal(FAKE_ADDRESS); - expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - }); - it('returns requested number of accounts', async () => { - const numberOfAccounts = 20; - const accounts = await ledgerSubprovider.getAccountsAsync(numberOfAccounts); - expect(accounts[0]).to.be.equal(FAKE_ADDRESS); - expect(accounts.length).to.be.equal(numberOfAccounts); - }); - it('signs a personal message', async () => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync(data, FAKE_ADDRESS); - expect(ecSignatureHex).to.be.equal( - '0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001', - ); - }); - }); - describe('failure cases', () => { - it('cannot open multiple simultaneous connections to the Ledger device', async () => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - return expect( - Promise.all([ - ledgerSubprovider.getAccountsAsync(), - ledgerSubprovider.signPersonalMessageAsync(data, FAKE_ADDRESS), - ]), - ).to.be.rejectedWith(LedgerSubproviderErrors.MultipleOpenConnectionsDisallowed); - }); - }); - }); - describe('calls through a provider', () => { - let provider: Web3ProviderEngine; - before(() => { - provider = new Web3ProviderEngine(); - provider.addProvider(ledgerSubprovider); - provider.addProvider(ganacheSubprovider); - provider.start(); - }); - describe('success cases', () => { - it('returns a list of accounts', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - expect(response.result[0]).to.be.equal(FAKE_ADDRESS); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message with eth_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [FAKE_ADDRESS, messageHex], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal( - '0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001', - ); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message with personal_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex, FAKE_ADDRESS], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal( - '0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001', - ); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a transaction', (done: DoneCallback) => { - const tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - value: '0x00', - gasPrice: '0x00', - nonce: '0x00', - gas: '0x00', - from: FAKE_ADDRESS, - }; - const payload = { - jsonrpc: '2.0', - method: 'eth_signTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - const rawTxLength = 192; - expect(response.result.raw.length).to.be.equal(rawTxLength); - expect(response.result.raw.substr(0, 2)).to.be.equal('0x'); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - describe('failure cases', () => { - it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [FAKE_ADDRESS, nonHexMessage], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [nonHexMessage, FAKE_ADDRESS], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `from` param missing when calling eth_sendTransaction', (done: DoneCallback) => { - const tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - value: '0xde0b6b3a7640000', - }; - const payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `from` param invalid address when calling eth_sendTransaction', (done: DoneCallback) => { - const tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - from: '0xIncorrectEthereumAddress', - value: '0xde0b6b3a7640000', - }; - const payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - }); -}); diff --git a/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts b/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts deleted file mode 100644 index 61dcbf6da..000000000 --- a/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts +++ /dev/null @@ -1,230 +0,0 @@ -import * as chai from 'chai'; -import { JSONRPCResponsePayload } from 'ethereum-types'; -import * as ethUtils from 'ethereumjs-util'; - -import { GanacheSubprovider, MnemonicWalletSubprovider, Web3ProviderEngine } from '../../src/'; -import { DoneCallback, WalletSubproviderErrors } from '../../src/types'; -import { chaiSetup } from '../chai_setup'; -import { fixtureData } from '../utils/fixture_data'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -chaiSetup.configure(); -const expect = chai.expect; -const DEFAULT_NUM_ACCOUNTS = 10; - -describe('MnemonicWalletSubprovider', () => { - let subprovider: MnemonicWalletSubprovider; - before(async () => { - subprovider = new MnemonicWalletSubprovider({ - mnemonic: fixtureData.TEST_RPC_MNEMONIC, - baseDerivationPath: fixtureData.TEST_RPC_MNEMONIC_BASE_DERIVATION_PATH, - }); - }); - describe('direct method calls', () => { - describe('success cases', () => { - it('returns the accounts', async () => { - const accounts = await subprovider.getAccountsAsync(); - expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(accounts[1]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_1); - expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - }); - it('signs a personal message', async () => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await subprovider.signPersonalMessageAsync(data, fixtureData.TEST_RPC_ACCOUNT_0); - expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - }); - it('signs a personal message with second address', async () => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await subprovider.signPersonalMessageAsync(data, fixtureData.TEST_RPC_ACCOUNT_1); - expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_ACCOUNT_1_SIGNED_RESULT); - }); - it('signs a transaction', async () => { - const txHex = await subprovider.signTransactionAsync(fixtureData.TX_DATA); - expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - }); - it('signs a transaction with the second address', async () => { - const txData = { ...fixtureData.TX_DATA, from: fixtureData.TEST_RPC_ACCOUNT_1 }; - const txHex = await subprovider.signTransactionAsync(txData); - expect(txHex).to.be.equal(fixtureData.TX_DATA_ACCOUNT_1_SIGNED_RESULT); - }); - it('signs an EIP712 sign typed data message', async () => { - const signature = await subprovider.signTypedDataAsync( - fixtureData.TEST_RPC_ACCOUNT_0, - fixtureData.EIP712_TEST_TYPED_DATA, - ); - expect(signature).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - }); - }); - describe('failure cases', () => { - it('throws an error if address is invalid ', async () => { - const txData = { ...fixtureData.TX_DATA, from: '0x0' }; - return expect(subprovider.signTransactionAsync(txData)).to.be.rejectedWith( - WalletSubproviderErrors.FromAddressMissingOrInvalid, - ); - }); - it('throws an error if address is valid format but not found', async () => { - const txData = { ...fixtureData.TX_DATA, from: fixtureData.NULL_ADDRESS }; - return expect(subprovider.signTransactionAsync(txData)).to.be.rejectedWith( - `${WalletSubproviderErrors.AddressNotFound}: ${fixtureData.NULL_ADDRESS}`, - ); - }); - }); - }); - describe('calls through a provider', () => { - let provider: Web3ProviderEngine; - before(() => { - provider = new Web3ProviderEngine(); - provider.addProvider(subprovider); - const ganacheSubprovider = new GanacheSubprovider({}); - provider.addProvider(ganacheSubprovider); - provider.start(); - }); - describe('success cases', () => { - it('returns a list of accounts', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message with eth_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [fixtureData.TEST_RPC_ACCOUNT_0, messageHex], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message with personal_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex, fixtureData.TEST_RPC_ACCOUNT_0], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs an EIP712 sign typed data message with eth_signTypedData', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTypedData', - params: [fixtureData.TEST_RPC_ACCOUNT_0, fixtureData.EIP712_TEST_TYPED_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - describe('failure cases', () => { - it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [fixtureData.TEST_RPC_ACCOUNT_0, nonHexMessage], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [nonHexMessage, fixtureData.TEST_RPC_ACCOUNT_0], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `address` param not found when calling personal_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex, fixtureData.NULL_ADDRESS], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal( - `${WalletSubproviderErrors.AddressNotFound}: ${fixtureData.NULL_ADDRESS}`, - ); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `from` param missing when calling eth_sendTransaction', (done: DoneCallback) => { - const tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - value: '0xde0b6b3a7640000', - }; - const payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `from` param invalid address when calling eth_sendTransaction', (done: DoneCallback) => { - const tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - from: '0xIncorrectEthereumAddress', - value: '0xde0b6b3a7640000', - }; - const payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - }); -}); diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts deleted file mode 100644 index a5cef30dc..000000000 --- a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import * as chai from 'chai'; -import FixtureSubprovider = require('web3-provider-engine/subproviders/fixture'); - -import { promisify } from '@0x/utils'; -import EthereumTx = require('ethereumjs-tx'); - -import { NonceTrackerSubprovider, Web3ProviderEngine } from '../../src'; -import { chaiSetup } from '../chai_setup'; - -const expect = chai.expect; -chaiSetup.configure(); - -describe('NonceTrackerSubprovider', () => { - let provider: Web3ProviderEngine; - const getTransactionCountPayload = { - jsonrpc: '2.0', - method: 'eth_getTransactionCount', - params: ['0x0', 'pending'], - id: 1, - }; - const sendTransactionPayload = { - jsonrpc: '2.0', - method: 'eth_sendRawTransaction', - params: [], - id: 1, - }; - const txParams = [ - '0x', - '0x09184e72a000', - '0x2710', - '0x0000000000000000000000000000000000000000', - '0x', - '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', - '0x1c', - '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab', - '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13', - ]; - function createFixtureSubprovider(): FixtureSubprovider { - let isFirstGetTransactionCount = true; - const fixedBlockNumberAndTransactionCountProvider = new FixtureSubprovider({ - eth_getBlockByNumber: '0x01', - eth_getTransactionCount: (_data: any, _next: any, end: any) => { - // For testing caching we return different results on the second call - if (isFirstGetTransactionCount) { - isFirstGetTransactionCount = false; - end(null, '0x00'); - } else { - end(null, '0x99'); - } - }, - }); - return fixedBlockNumberAndTransactionCountProvider; - } - it('successfully caches the transaction count', async () => { - provider = new Web3ProviderEngine(); - const nonceTrackerSubprovider = new NonceTrackerSubprovider(); - provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(createFixtureSubprovider()); - provider.start(); - - const payload = { ...getTransactionCountPayload, params: ['0x0', 'pending'] }; - - const response = await promisify<any>(provider.sendAsync.bind(provider))(payload); - expect(response.result).to.be.eq('0x00'); - const secondResponse = await promisify<any>(provider.sendAsync.bind(provider))(payload); - expect(secondResponse.result).to.be.eq('0x00'); - }); - it('does not cache the result for latest transaction count', async () => { - provider = new Web3ProviderEngine(); - const nonceTrackerSubprovider = new NonceTrackerSubprovider(); - provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(createFixtureSubprovider()); - provider.start(); - - const payload = { ...getTransactionCountPayload, params: ['0x0', 'latest'] }; - - const response = await promisify<any>(provider.sendAsync.bind(provider))(payload); - expect(response.result).to.be.eq('0x00'); - const secondResponse = await promisify<any>(provider.sendAsync.bind(provider))(payload); - expect(secondResponse.result).to.be.eq('0x99'); - }); - it('clears the cache on a Nonce Too Low Error', async () => { - provider = new Web3ProviderEngine(); - const nonceTrackerSubprovider = new NonceTrackerSubprovider(); - provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(createFixtureSubprovider()); - provider.addProvider( - new FixtureSubprovider({ - eth_sendRawTransaction: (_data: any, _next: any, end: any) => { - end(new Error('Transaction nonce is too low')); - }, - }), - ); - provider.start(); - - const noncePayload = { - ...getTransactionCountPayload, - params: ['0x1f36f546477cda21bf2296c50976f2740247906f', 'pending'], - }; - const transaction = new EthereumTx(txParams); - const txPayload = { - ...sendTransactionPayload, - params: [transaction.serialize()], - }; - - const response = await promisify<any>(provider.sendAsync.bind(provider))(noncePayload); - expect(response.result).to.be.eq('0x00'); - const secondResponse = await promisify<any>(provider.sendAsync.bind(provider))(noncePayload); - expect(secondResponse.result).to.be.eq('0x00'); - try { - await promisify(provider.sendAsync.bind(provider))(txPayload); - } catch (err) { - const thirdResponse = await promisify<any>(provider.sendAsync.bind(provider))(noncePayload); - expect(thirdResponse.result).to.be.eq('0x99'); - } - }); - it('increments the used nonce when a transaction successfully submits', async () => { - provider = new Web3ProviderEngine(); - const nonceTrackerSubprovider = new NonceTrackerSubprovider(); - provider.addProvider(nonceTrackerSubprovider); - provider.addProvider(createFixtureSubprovider()); - provider.addProvider( - new FixtureSubprovider({ - eth_sendRawTransaction: (_data: any, _next: any, end: any) => { - end(null); - }, - }), - ); - provider.start(); - - const noncePayload = { - ...getTransactionCountPayload, - params: ['0x1f36f546477cda21bf2296c50976f2740247906f', 'pending'], - }; - const transaction = new EthereumTx(txParams); - const txPayload = { - ...sendTransactionPayload, - params: [transaction.serialize()], - }; - - const response = await promisify<any>(provider.sendAsync.bind(provider))(noncePayload); - expect(response.result).to.be.eq('0x00'); - const secondResponse = await promisify<any>(provider.sendAsync.bind(provider))(noncePayload); - expect(secondResponse.result).to.be.eq('0x00'); - await promisify(provider.sendAsync.bind(provider))(txPayload); - const thirdResponse = await promisify<any>(provider.sendAsync.bind(provider))(noncePayload); - expect(thirdResponse.result).to.be.eq('0x01'); - }); -}); diff --git a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts b/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts deleted file mode 100644 index 4cd70e5ed..000000000 --- a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts +++ /dev/null @@ -1,232 +0,0 @@ -import * as chai from 'chai'; -import { JSONRPCResponsePayload } from 'ethereum-types'; -import * as ethUtils from 'ethereumjs-util'; - -import { GanacheSubprovider, PrivateKeyWalletSubprovider, Web3ProviderEngine } from '../../src/'; -import { DoneCallback, WalletSubproviderErrors } from '../../src/types'; -import { chaiSetup } from '../chai_setup'; -import { fixtureData } from '../utils/fixture_data'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('PrivateKeyWalletSubprovider', () => { - let subprovider: PrivateKeyWalletSubprovider; - before(async () => { - subprovider = new PrivateKeyWalletSubprovider(fixtureData.TEST_RPC_ACCOUNT_0_ACCOUNT_PRIVATE_KEY); - }); - describe('direct method calls', () => { - describe('success cases', () => { - it('returns the account', async () => { - const accounts = await subprovider.getAccountsAsync(); - expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(accounts.length).to.be.equal(1); - }); - it('signs a personal message', async () => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await subprovider.signPersonalMessageAsync(data, fixtureData.TEST_RPC_ACCOUNT_0); - expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - }); - it('signs a transaction', async () => { - const txHex = await subprovider.signTransactionAsync(fixtureData.TX_DATA); - expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - }); - it('signs an EIP712 sign typed data message', async () => { - const signature = await subprovider.signTypedDataAsync( - fixtureData.TEST_RPC_ACCOUNT_0, - fixtureData.EIP712_TEST_TYPED_DATA, - ); - expect(signature).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - }); - }); - }); - describe('calls through a provider', () => { - let provider: Web3ProviderEngine; - before(() => { - provider = new Web3ProviderEngine(); - provider.addProvider(subprovider); - const ganacheSubprovider = new GanacheSubprovider({}); - provider.addProvider(ganacheSubprovider); - provider.start(); - }); - describe('success cases', () => { - it('returns a list of accounts', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(response.result.length).to.be.equal(1); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a transaction', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTransaction', - params: [fixtureData.TX_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.raw).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message with eth_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [fixtureData.TEST_RPC_ACCOUNT_0, messageHex], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message with personal_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex, fixtureData.TEST_RPC_ACCOUNT_0], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs an EIP712 sign typed data message with eth_signTypedData', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTypedData', - params: [fixtureData.TEST_RPC_ACCOUNT_0, fixtureData.EIP712_TEST_TYPED_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - describe('failure cases', () => { - it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [fixtureData.TEST_RPC_ACCOUNT_0, nonHexMessage], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [nonHexMessage, fixtureData.TEST_RPC_ACCOUNT_0], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `address` param is not the address from private key when calling personal_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex, fixtureData.TEST_RPC_ACCOUNT_1], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal( - `Requested to sign message with address: ${ - fixtureData.TEST_RPC_ACCOUNT_1 - }, instantiated with address: ${fixtureData.TEST_RPC_ACCOUNT_0}`, - ); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `from` param missing when calling eth_sendTransaction', (done: DoneCallback) => { - const tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - value: '0xde0b6b3a7640000', - }; - const payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `from` param invalid address when calling eth_sendTransaction', (done: DoneCallback) => { - const tx = { - to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', - from: '0xIncorrectEthereumAddress', - value: '0xde0b6b3a7640000', - }; - const payload = { - jsonrpc: '2.0', - method: 'eth_sendTransaction', - params: [tx], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `address` param not found when calling personal_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex, '0x0'], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(`Expected address to be of type ETHAddressHex, encountered: 0x0`); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - }); -}); diff --git a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts deleted file mode 100644 index fb4e43f9e..000000000 --- a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { DoneCallback } from '@0x/types'; -import * as chai from 'chai'; -import { JSONRPCResponsePayload } from 'ethereum-types'; -import * as Sinon from 'sinon'; - -import { RedundantSubprovider, RPCSubprovider, Web3ProviderEngine } from '../../src'; -import { Subprovider } from '../../src/subproviders/subprovider'; -import { chaiSetup } from '../chai_setup'; -import { ganacheSubprovider } from '../utils/ganache_subprovider'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -const expect = chai.expect; -chaiSetup.configure(); -const DEFAULT_NUM_ACCOUNTS = 10; - -describe('RedundantSubprovider', () => { - let provider: Web3ProviderEngine; - it('succeeds when supplied a healthy endpoint', (done: DoneCallback) => { - provider = new Web3ProviderEngine(); - const subproviders = [ganacheSubprovider]; - const redundantSubprovider = new RedundantSubprovider(subproviders); - provider.addProvider(redundantSubprovider); - provider.start(); - - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('succeeds when supplied at least one healthy endpoint', (done: DoneCallback) => { - provider = new Web3ProviderEngine(); - const nonExistentSubprovider = new RPCSubprovider('http://does-not-exist:3000'); - const handleRequestStub = Sinon.stub(nonExistentSubprovider, 'handleRequest').throws( - new Error('REQUEST_FAILED'), - ); - const subproviders = [nonExistentSubprovider as Subprovider, ganacheSubprovider]; - const redundantSubprovider = new RedundantSubprovider(subproviders); - provider.addProvider(redundantSubprovider); - provider.start(); - - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - handleRequestStub.restore(); - done(); - }); - provider.sendAsync(payload, callback); - }); -}); diff --git a/packages/subproviders/test/utils/configs.ts b/packages/subproviders/test/utils/configs.ts deleted file mode 100644 index 341037e4f..000000000 --- a/packages/subproviders/test/utils/configs.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const configs = { - port: 8545, - networkId: 50, - mnemonic: 'concert load couple harbor equip island argue ramp clarify fence smart topic', -}; diff --git a/packages/subproviders/test/utils/fixture_data.ts b/packages/subproviders/test/utils/fixture_data.ts deleted file mode 100644 index 3eb4493b5..000000000 --- a/packages/subproviders/test/utils/fixture_data.ts +++ /dev/null @@ -1,64 +0,0 @@ -const TEST_RPC_ACCOUNT_0 = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; -const TEST_RPC_ACCOUNT_1 = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb'; -const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; -const networkId = 42; -export const fixtureData = { - NULL_ADDRESS, - TEST_RPC_ACCOUNT_0, - TEST_RPC_ACCOUNT_0_ACCOUNT_PRIVATE_KEY: 'F2F48EE19680706196E2E339E5DA3491186E0C4C5030670656B0E0164837257D', - TEST_RPC_ACCOUNT_1, - TEST_RPC_MNEMONIC: 'concert load couple harbor equip island argue ramp clarify fence smart topic', - TEST_RPC_MNEMONIC_BASE_DERIVATION_PATH: `44'/60'/0'/0`, - PERSONAL_MESSAGE_STRING: 'hello world', - PERSONAL_MESSAGE_SIGNED_RESULT: - '0x1b0ec5e2908e993d0c8ab6b46da46be2688fdf03c7ea6686075de37392e50a7d7fcc531446699132fbda915bd989882e0064d417018773a315fb8d43ed063c9b00', - PERSONAL_MESSAGE_ACCOUNT_1_SIGNED_RESULT: - '0xe7ae0c21d02eb38f2c2a20d9d7876a98cc7ef035b7a4559d49375e2ec735e06f0d0ab0ff92ee56c5ffc28d516e6ed0692d0270feae8796408dbef060c6c7100f01', - TESTRPC_BASE_DERIVATION_PATH: `m/44'/60'/0'/0`, - NETWORK_ID: networkId, - TX_DATA: { - nonce: '0x00', - gasPrice: '0x0', - gas: '0x2710', - to: NULL_ADDRESS, - value: '0x00', - chainId: networkId, - from: TEST_RPC_ACCOUNT_0, - }, - // This is the signed result of the above Transaction Data - TX_DATA_SIGNED_RESULT: - '0xf85f8080822710940000000000000000000000000000000000000000808078a0712854c73c69445cc1b22a7c3d7312ff9a97fe4ffba35fd636e8236b211b6e7ca0647cee031615e52d916c7c707025bc64ad525d8f1b9876c3435a863b42743178', - TX_DATA_ACCOUNT_1_SIGNED_RESULT: - '0xf85f8080822710940000000000000000000000000000000000000000808078a04b02af7ff3f18ce114b601542cc8ebdc50921354f75dd510d31793453a0710e6a0540082a01e475465801b8186a2edc79ec1a2dcf169b9781c25a58a417023c9ca', - EIP712_TEST_TYPED_DATA: { - types: { - EIP712Domain: [ - { - name: 'name', - type: 'string', - }, - ], - Test: [ - { - name: 'testAddress', - type: 'address', - }, - { - name: 'testNumber', - type: 'uint256', - }, - ], - }, - domain: { - name: 'Test', - }, - message: { - testAddress: '0x0000000000000000000000000000000000000000', - testNumber: '12345', - }, - primaryType: 'Test', - }, - EIP712_TEST_TYPED_DATA_HASH: '0xb460d69ca60383293877cd765c0f97bd832d66bca720f7e32222ce1118832493', - EIP712_TEST_TYPED_DATA_SIGNED_RESULT: - '0x20af5b6bfc3658942198d6eeda159b4ed589f90cee6eac3ba117818ffba5fd7e354a353aad93faabd6eb6c66e17921c92bd1cd09c92a770f554470dc3e254ce701', -}; diff --git a/packages/subproviders/test/utils/ganache_subprovider.ts b/packages/subproviders/test/utils/ganache_subprovider.ts deleted file mode 100644 index ac4a9325c..000000000 --- a/packages/subproviders/test/utils/ganache_subprovider.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as fs from 'fs'; - -import { GanacheSubprovider } from '../../src/subproviders/ganache'; -import { configs } from '../utils/configs'; - -const logger = { - log: (arg: any) => { - fs.appendFileSync('ganache.log', `${arg}\n`); - }, -}; - -export const ganacheSubprovider = new GanacheSubprovider({ - logger, - verbose: false, - port: configs.port, - networkId: configs.networkId, - mnemonic: configs.mnemonic, -}); diff --git a/packages/subproviders/test/utils/report_callback_errors.ts b/packages/subproviders/test/utils/report_callback_errors.ts deleted file mode 100644 index 6eb7420c3..000000000 --- a/packages/subproviders/test/utils/report_callback_errors.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { DoneCallback } from '@0x/types'; - -export const reportCallbackErrors = (done: DoneCallback) => { - return (f: (...args: any[]) => void) => { - const wrapped = async (...args: any[]) => { - try { - f(...args); - } catch (err) { - done(err); - } - }; - return wrapped; - }; -}; diff --git a/packages/subproviders/tsconfig.json b/packages/subproviders/tsconfig.json deleted file mode 100644 index 2ee711adc..000000000 --- a/packages/subproviders/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { - "outDir": "lib", - "rootDir": "." - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/packages/subproviders/tslint.json b/packages/subproviders/tslint.json deleted file mode 100644 index dd9053357..000000000 --- a/packages/subproviders/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["@0x/tslint-config"] -} diff --git a/packages/subproviders/typedoc-tsconfig.json b/packages/subproviders/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae..000000000 --- a/packages/subproviders/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} |