diff options
author | Remco Bloemen <remco@wicked.ventures> | 2018-11-09 01:32:40 +0800 |
---|---|---|
committer | Remco Bloemen <remco@wicked.ventures> | 2018-11-09 01:32:40 +0800 |
commit | d71362af993d3797dbdbfcac245ad57f0086bce3 (patch) | |
tree | 888826fe23c2d06d6c9191fb3a238e14f9fe4aac /packages/subproviders | |
parent | a5665a68756c905637c551fc48c9b7011a55c237 (diff) | |
parent | f6abc007ffb249e4bbf85b8a7a77309d43e0a147 (diff) | |
download | dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.gz dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.bz2 dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.lz dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.xz dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.zst dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.zip |
Merge remote-tracking branch 'origin/development' into feature/utils/prettybignum
Diffstat (limited to 'packages/subproviders')
31 files changed, 593 insertions, 106 deletions
diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json index 93939066a..b145bbbe5 100644 --- a/packages/subproviders/CHANGELOG.json +++ b/packages/subproviders/CHANGELOG.json @@ -1,5 +1,97 @@ [ { + "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": [ diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index 152c0027e..f9e3e63a6 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -5,7 +5,45 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## 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 diff --git a/packages/subproviders/README.md b/packages/subproviders/README.md index 90c9b7bbe..6f97d760e 100644 --- a/packages/subproviders/README.md +++ b/packages/subproviders/README.md @@ -1,4 +1,4 @@ -## @0xproject/subproviders +## @0x/subproviders A few useful web3 subproviders including a LedgerSubprovider useful for adding Ledger Nano S support. @@ -9,14 +9,14 @@ We have written up a [Wiki](https://0xproject.com/wiki#Web3-Provider-Examples) a ## Installation ``` -yarn add @0xproject/subproviders +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/@0xproject/typescript-typings/types", "node_modules/@types"], + "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"], } ``` @@ -45,13 +45,13 @@ yarn install To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: ```bash -PKG=@0xproject/subproviders yarn build +PKG=@0x/subproviders yarn build ``` Or continuously rebuild on change: ```bash -PKG=@0xproject/subproviders yarn watch +PKG=@0x/subproviders yarn watch ``` ### Clean diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index 57b0a13b3..32e2bae24 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,6 +1,6 @@ { - "name": "@0xproject/subproviders", - "version": "1.0.5", + "name": "@0x/subproviders", + "version": "2.1.0", "engines": { "node": ">=6.12" }, @@ -8,10 +8,10 @@ "types": "lib/src/index.d.ts", "license": "Apache-2.0", "scripts": { - "watch_without_deps": "tsc -w", - "build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts", - "clean": "shx rm -rf lib scripts", - "lint": "tslint --project .", + "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", @@ -21,40 +21,32 @@ "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", - "manual:postpublish": "yarn build; node ./scripts/postpublish.js", - "docs:stage": "node scripts/stage_docs.js", - "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES", - "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json" + "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" }, "config": { "postpublish": { - "assets": [], - "docPublishConfigs": { - "extraFileIncludes": [ - "../types/src/index.ts", - "../ethereum-types/src/index.ts" - ], - "s3BucketPath": "s3://doc-jsons/subproviders/", - "s3StagingBucketPath": "s3://staging-doc-jsons/subproviders/" - } + "assets": [] } }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0x/assert": "^1.0.14", + "@0x/types": "^1.2.0", + "@0x/typescript-typings": "^3.0.3", + "@0x/utils": "^2.0.3", + "@0x/web3-wrapper": "^3.1.0", "@ledgerhq/hw-app-eth": "^4.3.0", "@ledgerhq/hw-transport-u2f": "^4.3.0", + "@types/eth-lightwallet": "^3.0.0", + "@types/ganache-core": "^2.1.0", "@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": "^1.0.4", + "ethereum-types": "^1.1.1", "ethereumjs-tx": "^1.3.5", "ethereumjs-util": "^5.1.1", - "ganache-core": "0xProject/ganache-core#monorepo-dep", + "ganache-core": "^2.2.1", "hdkey": "^0.7.1", "json-rpc-error": "2.0.0", "lodash": "^4.17.5", @@ -62,19 +54,17 @@ "web3-provider-engine": "14.0.6" }, "devDependencies": { - "@0xproject/monorepo-scripts": "^1.0.5", - "@0xproject/tslint-config": "^1.0.5", + "@0x/tslint-config": "^1.0.9", "@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": "^8.0.53", + "@types/node": "*", "@types/sinon": "^2.2.2", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", - "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", @@ -83,9 +73,9 @@ "shx": "^0.2.2", "sinon": "^4.0.0", "tslint": "5.11.0", - "typedoc": "0xProject/typedoc", + "typedoc": "0.13.0", "typescript": "3.0.1", - "webpack": "^3.1.0" + "webpack": "^4.20.2" }, "optionalDependencies": { "@ledgerhq/hw-transport-node-hid": "^4.3.0" diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index 94e63a32d..3cbf84e37 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -4,3 +4,21 @@ declare module '*.json' { 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 index 9d4480e59..050027f96 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -1,11 +1,21 @@ import Eth from '@ledgerhq/hw-app-eth'; import TransportU2F from '@ledgerhq/hw-transport-u2f'; export import Web3ProviderEngine = require('web3-provider-engine'); -export { ECSignature } from '@0xproject/types'; 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'; @@ -17,7 +27,9 @@ 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, @@ -26,14 +38,22 @@ export { LedgerEthereumClient, NonceSubproviderErrors, LedgerSubproviderConfigs, + PartialTxParams, + JSONRPCRequestPayloadWithMethod, + ECSignatureString, + AccountFetchingConfigs, + LedgerEthereumClientFactoryAsync, + OnNextCompleted, + MnemonicWalletSubproviderConfigs, + LedgerGetAddressResult, } 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 { ECSignature, EIP712Object, EIP712ObjectValue, EIP712TypedData, EIP712Types, EIP712Parameter } from '@0x/types'; + +export { + JSONRPCRequestPayload, + Provider, + JSONRPCResponsePayload, + JSONRPCErrorCallback, + JSONRPCResponseError, +} from 'ethereum-types'; diff --git a/packages/subproviders/src/monorepo_scripts/postpublish.ts b/packages/subproviders/src/monorepo_scripts/postpublish.ts deleted file mode 100644 index dcb99d0f7..000000000 --- a/packages/subproviders/src/monorepo_scripts/postpublish.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { postpublishUtils } from '@0xproject/monorepo-scripts'; - -import * as packageJSON from '../package.json'; -import * as tsConfigJSON from '../tsconfig.json'; - -const cwd = `${__dirname}/..`; -// tslint:disable-next-line:no-floating-promises -postpublishUtils.runAsync(packageJSON, tsConfigJSON, cwd); diff --git a/packages/subproviders/src/monorepo_scripts/stage_docs.ts b/packages/subproviders/src/monorepo_scripts/stage_docs.ts deleted file mode 100644 index e732ac8eb..000000000 --- a/packages/subproviders/src/monorepo_scripts/stage_docs.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { postpublishUtils } from '@0xproject/monorepo-scripts'; - -import * as packageJSON from '../package.json'; -import * as tsConfigJSON from '../tsconfig.json'; - -const cwd = `${__dirname}/..`; -// tslint:disable-next-line:no-floating-promises -postpublishUtils.publishDocsToStagingAsync(packageJSON, tsConfigJSON, cwd); diff --git a/packages/subproviders/src/subproviders/base_wallet_subprovider.ts b/packages/subproviders/src/subproviders/base_wallet_subprovider.ts index 4342e47e9..e9d104074 100644 --- a/packages/subproviders/src/subproviders/base_wallet_subprovider.ts +++ b/packages/subproviders/src/subproviders/base_wallet_subprovider.ts @@ -1,5 +1,5 @@ -import { assert } from '@0xproject/assert'; -import { addressUtils } from '@0xproject/utils'; +import { assert } from '@0x/assert'; +import { addressUtils } from '@0x/utils'; import { JSONRPCRequestPayload, JSONRPCResponsePayload } from 'ethereum-types'; import * as _ from 'lodash'; @@ -23,6 +23,7 @@ export abstract class BaseWalletSubprovider extends Subprovider { 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. @@ -36,6 +37,8 @@ export abstract class BaseWalletSubprovider extends Subprovider { 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 { @@ -86,7 +89,7 @@ export abstract class BaseWalletSubprovider extends Subprovider { case 'eth_sign': case 'personal_sign': const data = payload.method === 'eth_sign' ? payload.params[1] : payload.params[0]; - const address = payload.method === 'eth_sign' ? payload.params[0] : payload.params[1]; + address = payload.method === 'eth_sign' ? payload.params[0] : payload.params[1]; try { const ecSignatureHex = await this.signPersonalMessageAsync(data, address); end(null, ecSignatureHex); @@ -94,6 +97,15 @@ export abstract class BaseWalletSubprovider extends Subprovider { 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(); diff --git a/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts b/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts index 454dae58e..15cd713af 100644 --- a/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts +++ b/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts @@ -1,3 +1,4 @@ +import { EIP712TypedData } from '@0x/types'; import * as lightwallet from 'eth-lightwallet'; import { PartialTxParams } from '../types'; @@ -14,6 +15,12 @@ import { PrivateKeyWalletSubprovider } from './private_key_wallet'; 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; @@ -42,16 +49,16 @@ export class EthLightwalletSubprovider extends BaseWalletSubprovider { // 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 privKey = this._keystore.exportPrivateKey(txParams.from, this._pwDerivedKey); - const privKeyWallet = new PrivateKeyWalletSubprovider(privKey); - privKey = ''; - const privKeySignature = await privKeyWallet.signTransactionAsync(txParams); - return privKeySignature; + 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 the MnemonicWalletSubprovider to your app's provider, you can simply send an `eth_sign` + * 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 @@ -59,10 +66,26 @@ export class EthLightwalletSubprovider extends BaseWalletSubprovider { * @return Signature hex string (order: rsv) */ public async signPersonalMessageAsync(data: string, address: string): Promise<string> { - let privKey = this._keystore.exportPrivateKey(address, this._pwDerivedKey); - const privKeyWallet = new PrivateKeyWalletSubprovider(privKey); - privKey = ''; - const result = privKeyWallet.signPersonalMessageAsync(data, address); + 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/ganache.ts b/packages/subproviders/src/subproviders/ganache.ts index 986094dba..2b8544f8b 100644 --- a/packages/subproviders/src/subproviders/ganache.ts +++ b/packages/subproviders/src/subproviders/ganache.ts @@ -24,7 +24,7 @@ export class GanacheSubprovider extends Subprovider { * 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 _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 diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index 6ad5de2e2..28e348f90 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -1,5 +1,5 @@ -import { assert } from '@0xproject/assert'; -import { addressUtils } from '@0xproject/utils'; +import { assert } from '@0x/assert'; +import { addressUtils } from '@0x/utils'; import EthereumTx = require('ethereumjs-tx'); import ethUtil = require('ethereumjs-util'); import HDNode = require('hdkey'); @@ -187,6 +187,16 @@ export class LedgerSubprovider extends BaseWalletSubprovider { 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)) { diff --git a/packages/subproviders/src/subproviders/metamask_subprovider.ts b/packages/subproviders/src/subproviders/metamask_subprovider.ts new file mode 100644 index 000000000..ba207d4cc --- /dev/null +++ b/packages/subproviders/src/subproviders/metamask_subprovider.ts @@ -0,0 +1,126 @@ +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 index 1495112b6..140e3d515 100644 --- a/packages/subproviders/src/subproviders/mnemonic_wallet.ts +++ b/packages/subproviders/src/subproviders/mnemonic_wallet.ts @@ -1,5 +1,6 @@ -import { assert } from '@0xproject/assert'; -import { addressUtils } from '@0xproject/utils'; +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'; @@ -90,10 +91,10 @@ export class MnemonicWalletSubprovider extends BaseWalletSubprovider { } /** * 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. + * 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) @@ -108,6 +109,25 @@ export class MnemonicWalletSubprovider extends BaseWalletSubprovider { 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'); diff --git a/packages/subproviders/src/subproviders/private_key_wallet.ts b/packages/subproviders/src/subproviders/private_key_wallet.ts index 9d6fc487e..dca7e6810 100644 --- a/packages/subproviders/src/subproviders/private_key_wallet.ts +++ b/packages/subproviders/src/subproviders/private_key_wallet.ts @@ -1,4 +1,6 @@ -import { assert } from '@0xproject/assert'; +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'; @@ -23,7 +25,7 @@ export class PrivateKeyWalletSubprovider extends BaseWalletSubprovider { constructor(privateKey: string) { assert.isString('privateKey', privateKey); super(); - this._privateKeyBuffer = new Buffer(privateKey, 'hex'); + this._privateKeyBuffer = Buffer.from(privateKey, 'hex'); this._address = `0x${ethUtil.privateToAddress(this._privateKeyBuffer).toString('hex')}`; } /** @@ -84,4 +86,29 @@ export class PrivateKeyWalletSubprovider extends BaseWalletSubprovider { 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 index 7aa6226d5..58312f203 100644 --- a/packages/subproviders/src/subproviders/redundant_subprovider.ts +++ b/packages/subproviders/src/subproviders/redundant_subprovider.ts @@ -1,4 +1,4 @@ -import { promisify } from '@0xproject/utils'; +import { promisify } from '@0x/utils'; import { JSONRPCRequestPayload } from 'ethereum-types'; import * as _ from 'lodash'; @@ -34,7 +34,7 @@ export class RedundantSubprovider extends Subprovider { } /** * Instantiates a new RedundantSubprovider - * @param endpoints JSON RPC endpoints to attempt. Attempts are made in the order of the endpoints. + * @param subproviders Subproviders to attempt the request with */ constructor(subproviders: Subprovider[]) { super(); diff --git a/packages/subproviders/src/subproviders/rpc_subprovider.ts b/packages/subproviders/src/subproviders/rpc_subprovider.ts index d874c6f05..437518e12 100644 --- a/packages/subproviders/src/subproviders/rpc_subprovider.ts +++ b/packages/subproviders/src/subproviders/rpc_subprovider.ts @@ -1,6 +1,6 @@ -import { assert } from '@0xproject/assert'; -import { StatusCodes } from '@0xproject/types'; -import { fetchAsync } from '@0xproject/utils'; +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'); @@ -15,6 +15,10 @@ import { Subprovider } from './subprovider'; 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); @@ -27,7 +31,7 @@ export class RPCSubprovider extends Subprovider { * 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 _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 diff --git a/packages/subproviders/src/subproviders/signer.ts b/packages/subproviders/src/subproviders/signer.ts index d5fd86897..9bd5cbdf1 100644 --- a/packages/subproviders/src/subproviders/signer.ts +++ b/packages/subproviders/src/subproviders/signer.ts @@ -1,4 +1,4 @@ -import { marshaller, Web3Wrapper } from '@0xproject/web3-wrapper'; +import { marshaller, Web3Wrapper } from '@0x/web3-wrapper'; import { JSONRPCRequestPayload, Provider } from 'ethereum-types'; import { Callback, ErrorCallback } from '../types'; @@ -14,7 +14,7 @@ import { Subprovider } from './subprovider'; export class SignerSubprovider extends Subprovider { private readonly _web3Wrapper: Web3Wrapper; /** - * Instantiates a new SignerSubprovider + * Instantiates a new SignerSubprovider. * @param provider Web3 provider that should handle all user account related requests */ constructor(provider: Provider) { @@ -31,6 +31,8 @@ export class SignerSubprovider extends Subprovider { */ // 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 { @@ -59,7 +61,7 @@ export class SignerSubprovider extends Subprovider { } return; case 'eth_sign': - const [address, message] = payload.params; + [address, message] = payload.params; try { const signature = await this._web3Wrapper.signMessageAsync(address, message); end(null, signature); @@ -67,6 +69,15 @@ export class SignerSubprovider extends Subprovider { 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 index 5dc273569..cd6780e0c 100644 --- a/packages/subproviders/src/subproviders/subprovider.ts +++ b/packages/subproviders/src/subproviders/subprovider.ts @@ -1,4 +1,4 @@ -import { promisify } from '@0xproject/utils'; +import { promisify } from '@0x/utils'; import { JSONRPCRequestPayload, JSONRPCResponsePayload, Provider } from 'ethereum-types'; import { Callback, ErrorCallback, JSONRPCRequestPayloadWithMethod } from '../types'; @@ -32,6 +32,11 @@ export abstract class Subprovider { // 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, @@ -48,6 +53,8 @@ export abstract class Subprovider { */ 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; } @@ -55,6 +62,7 @@ export abstract class Subprovider { * 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 index fe58bffa5..ed3aea176 100644 --- a/packages/subproviders/src/types.ts +++ b/packages/subproviders/src/types.ts @@ -1,4 +1,4 @@ -import { ECSignature } from '@0xproject/types'; +import { ECSignature } from '@0x/types'; import { JSONRPCRequestPayload } from 'ethereum-types'; import HDNode = require('hdkey'); @@ -107,8 +107,10 @@ export interface ResponseWithTxParams { 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', diff --git a/packages/subproviders/test/integration/ledger_subprovider_test.ts b/packages/subproviders/test/integration/ledger_subprovider_test.ts index 527ee5b22..b072e611b 100644 --- a/packages/subproviders/test/integration/ledger_subprovider_test.ts +++ b/packages/subproviders/test/integration/ledger_subprovider_test.ts @@ -1,5 +1,5 @@ -import { DoneCallback } from '@0xproject/types'; -import { promisify } from '@0xproject/utils'; +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 diff --git a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts index 063817a95..49698ce9e 100644 --- a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts +++ b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts @@ -73,6 +73,13 @@ describe('EthLightwalletSubprovider', () => { 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', () => { @@ -129,6 +136,20 @@ describe('EthLightwalletSubprovider', () => { }); 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) => { diff --git a/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts b/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts index f2bdda3cd..61dcbf6da 100644 --- a/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts +++ b/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts @@ -47,6 +47,13 @@ describe('MnemonicWalletSubprovider', () => { 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 () => { @@ -118,6 +125,20 @@ describe('MnemonicWalletSubprovider', () => { }); 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) => { diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts index 05f213cf5..a5cef30dc 100644 --- a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts +++ b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts @@ -1,7 +1,7 @@ import * as chai from 'chai'; import FixtureSubprovider = require('web3-provider-engine/subproviders/fixture'); -import { promisify } from '@0xproject/utils'; +import { promisify } from '@0x/utils'; import EthereumTx = require('ethereumjs-tx'); import { NonceTrackerSubprovider, Web3ProviderEngine } from '../../src'; diff --git a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts b/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts index 95773145f..4cd70e5ed 100644 --- a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts +++ b/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts @@ -32,6 +32,13 @@ describe('PrivateKeyWalletSubprovider', () => { 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', () => { @@ -103,6 +110,20 @@ describe('PrivateKeyWalletSubprovider', () => { }); 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) => { diff --git a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts index e30d2f74e..fb4e43f9e 100644 --- a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts +++ b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts @@ -1,4 +1,4 @@ -import { DoneCallback } from '@0xproject/types'; +import { DoneCallback } from '@0x/types'; import * as chai from 'chai'; import { JSONRPCResponsePayload } from 'ethereum-types'; import * as Sinon from 'sinon'; diff --git a/packages/subproviders/test/utils/fixture_data.ts b/packages/subproviders/test/utils/fixture_data.ts index 7cf502c97..3eb4493b5 100644 --- a/packages/subproviders/test/utils/fixture_data.ts +++ b/packages/subproviders/test/utils/fixture_data.ts @@ -30,4 +30,35 @@ export const fixtureData = { '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/report_callback_errors.ts b/packages/subproviders/test/utils/report_callback_errors.ts index eaefea7c3..6eb7420c3 100644 --- a/packages/subproviders/test/utils/report_callback_errors.ts +++ b/packages/subproviders/test/utils/report_callback_errors.ts @@ -1,4 +1,4 @@ -import { DoneCallback } from '@0xproject/types'; +import { DoneCallback } from '@0x/types'; export const reportCallbackErrors = (done: DoneCallback) => { return (f: (...args: any[]) => void) => { diff --git a/packages/subproviders/tsconfig.json b/packages/subproviders/tsconfig.json index e35816553..2ee711adc 100644 --- a/packages/subproviders/tsconfig.json +++ b/packages/subproviders/tsconfig.json @@ -1,7 +1,8 @@ { "extends": "../../tsconfig", "compilerOptions": { - "outDir": "lib" + "outDir": "lib", + "rootDir": "." }, "include": ["./src/**/*", "./test/**/*"] } diff --git a/packages/subproviders/tslint.json b/packages/subproviders/tslint.json index ffaefe83a..dd9053357 100644 --- a/packages/subproviders/tslint.json +++ b/packages/subproviders/tslint.json @@ -1,3 +1,3 @@ { - "extends": ["@0xproject/tslint-config"] + "extends": ["@0x/tslint-config"] } diff --git a/packages/subproviders/typedoc-tsconfig.json b/packages/subproviders/typedoc-tsconfig.json new file mode 100644 index 000000000..c9b0af1ae --- /dev/null +++ b/packages/subproviders/typedoc-tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../typedoc-tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "./test/**/*"] +} |