Introduce Metamask Subprovider.

MM has a number of inconsistencies with other providers when implementing the JSON RPC interface. This subprovider wraps those nuances so they do not leak into the rest of our code
This commit is contained in:
Jacob Evans 2018-10-02 17:32:28 +10:00
parent adcfaa2e80
commit 07926ded6e
No known key found for this signature in database
GPG Key ID: 2036DA2ADDFB0842
15 changed files with 277 additions and 444 deletions

View File

@ -53,7 +53,13 @@ export { OrderWatcher, OnOrderStateChangeCallback, OrderWatcherConfig } from '@0
export import Web3ProviderEngine = require('web3-provider-engine');
export { RPCSubprovider, Callback, JSONRPCRequestPayloadWithMethod, ErrorCallback } from '@0xproject/subproviders';
export {
RPCSubprovider,
Callback,
JSONRPCRequestPayloadWithMethod,
ErrorCallback,
MetamaskSubprovider,
} from '@0xproject/subproviders';
export { AbiDecoder } from '@0xproject/utils';
@ -68,7 +74,6 @@ export {
OrderStateInvalid,
OrderState,
AssetProxyId,
SignerType,
ERC20AssetData,
ERC721AssetData,
SignatureType,

View File

@ -1,7 +1,7 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { FillScenarios } from '@0xproject/fill-scenarios';
import { assetDataUtils, generatePseudoRandomSalt, orderHashUtils, signatureUtils } from '@0xproject/order-utils';
import { SignedOrder, SignerType } from '@0xproject/types';
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import 'mocha';
@ -80,12 +80,7 @@ describe('TransactionEncoder', () => {
): Promise<void> => {
const salt = generatePseudoRandomSalt();
const encodedTransaction = encoder.getTransactionHex(data, salt, signerAddress);
const signature = await signatureUtils.ecSignOrderHashAsync(
provider,
encodedTransaction,
signerAddress,
SignerType.Default,
);
const signature = await signatureUtils.ecSignHashAsync(provider, encodedTransaction, signerAddress);
txHash = await contractWrappers.exchange.executeTransactionAsync(
salt,
signerAddress,

View File

@ -1,6 +1,6 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { assetDataUtils, orderHashUtils, signatureUtils } from '@0xproject/order-utils';
import { RevertReason, SignatureType, SignedOrder, SignerType } from '@0xproject/types';
import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types';
import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types';
import ethUtil = require('ethereumjs-util');
@ -231,10 +231,7 @@ describe('MixinSignatureValidator', () => {
it('should return true when SignatureType=EthSign and signature is valid', async () => {
// Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
SignerType.Default,
);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature
@ -257,10 +254,7 @@ describe('MixinSignatureValidator', () => {
it('should return false when SignatureType=EthSign and signature is invalid', async () => {
// Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
SignerType.Default,
);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature

View File

@ -29,7 +29,6 @@ export {
ERC20AssetData,
ERC721AssetData,
AssetProxyId,
SignerType,
SignatureType,
OrderStateValid,
OrderStateInvalid,

View File

@ -1,4 +1,4 @@
import { Order, SignedOrder, SignerType } from '@0xproject/types';
import { Order, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
@ -71,12 +71,7 @@ export const orderFactory = {
createOrderOpts,
);
const orderHash = orderHashUtils.getOrderHashHex(order);
const signature = await signatureUtils.ecSignOrderHashAsync(
provider,
orderHash,
makerAddress,
SignerType.Default,
);
const signature = await signatureUtils.ecSignHashAsync(provider, orderHash, makerAddress);
const signedOrder: SignedOrder = _.assign(order, { signature });
return signedOrder;
},

View File

@ -1,5 +1,5 @@
import { schemas } from '@0xproject/json-schemas';
import { ECSignature, Order, SignatureType, SignerType, ValidatorSignature } from '@0xproject/types';
import { ECSignature, Order, SignatureType, ValidatorSignature } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as ethUtil from 'ethereumjs-util';
@ -11,7 +11,7 @@ import { EIP712_DOMAIN_NAME, EIP712_DOMAIN_SCHEMA, EIP712_DOMAIN_VERSION } from
import { ExchangeContract } from './generated_contract_wrappers/exchange';
import { IValidatorContract } from './generated_contract_wrappers/i_validator';
import { IWalletContract } from './generated_contract_wrappers/i_wallet';
import { EIP712_ORDER_SCHEMA } from './order_hash';
import { EIP712_ORDER_SCHEMA, orderHashUtils } from './order_hash';
import { OrderError } from './types';
import { utils } from './utils';
@ -51,7 +51,7 @@ export const signatureUtils = {
case SignatureType.EthSign: {
const ecSignature = signatureUtils.parseECSignature(signature);
const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, SignerType.Default);
const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data);
return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
}
@ -194,19 +194,41 @@ export const signatureUtils = {
}
},
/**
* Signs an order using `eth_signTypedData` and returns it's elliptic curve signature and signature type.
* This method currently supports Ganache.
* Signs an order and returns its elliptic curve signature and signature type. First `eth_signTypedData` is requested
* then a fallback to `eth_sign` if not available on this provider.
* @param order The Order to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
* must be available via the Provider supplied to 0x.js.
* @return A hex encoded string containing the Elliptic curve signature generated by signing the orderHash and the Signature Type.
*/
async ecSignOrderAsync(provider: Provider, order: Order, signerAddress: string): Promise<string> {
try {
const signatureHex = signatureUtils.ecSignTypedDataOrderAsync(provider, order, signerAddress);
return signatureHex;
} catch (err) {
// Fallback to using EthSign when ethSignTypedData is not supported
const orderHash = orderHashUtils.getOrderHashHex(order);
const signatureHex = await signatureUtils.ecSignHashAsync(provider, orderHash, signerAddress);
return signatureHex;
}
},
/**
* Signs an order using `eth_signTypedData` and returns its elliptic curve signature and signature type.
* @param order The Order to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
* must be available via the Provider supplied to 0x.js.
* @return A hex encoded string containing the Elliptic curve signature generated by signing the order with `eth_signTypedData`
* and the Signature Type.
*/
async ecSignTypedDataOrderAsync(provider: Provider, order: Order, signerAddress: string): Promise<string> {
assert.isWeb3Provider('provider', provider);
assert.isETHAddressHex('signerAddress', signerAddress);
const web3Wrapper = new Web3Wrapper(provider);
await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper);
const normalizedSignerAddress = signerAddress.toLowerCase();
const normalizedOrder = _.mapValues(order, value => {
return _.isObject(value) ? value.toString() : value;
});
const typedData = {
types: {
EIP712Domain: EIP712_DOMAIN_SCHEMA.parameters,
@ -217,15 +239,7 @@ export const signatureUtils = {
version: EIP712_DOMAIN_VERSION,
verifyingContract: order.exchangeAddress,
},
message: {
...order,
salt: order.salt.toString(),
makerFee: order.makerFee.toString(),
takerFee: order.takerFee.toString(),
makerAssetAmount: order.makerAssetAmount.toString(),
takerAssetAmount: order.takerAssetAmount.toString(),
expirationTimeSeconds: order.expirationTimeSeconds.toString(),
},
message: normalizedOrder,
primaryType: 'Order',
};
const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData);
@ -240,36 +254,23 @@ export const signatureUtils = {
return signatureHex;
},
/**
* Signs an orderHash and returns it's elliptic curve signature and signature type.
* Signs a hash and returns its elliptic curve signature and signature type.
* This method currently supports TestRPC, Geth and Parity above and below V1.6.6
* @param orderHash Hex encoded orderHash to sign.
* @param msgHash Hex encoded message to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
* must be available via the Provider supplied to 0x.js.
* @param signerType Different signers add/require different prefixes to be prepended to the message being signed.
* Since we cannot know ahead of time which signer you are using, you must supply a SignerType.
* @return A hex encoded string containing the Elliptic curve signature generated by signing the orderHash and the Signature Type.
* @return A hex encoded string containing the Elliptic curve signature generated by signing the msgHash and the Signature Type.
*/
async ecSignOrderHashAsync(
provider: Provider,
orderHash: string,
signerAddress: string,
signerType: SignerType,
): Promise<string> {
async ecSignHashAsync(provider: Provider, msgHash: string, signerAddress: string): Promise<string> {
assert.isWeb3Provider('provider', provider);
assert.isHexString('orderHash', orderHash);
assert.isHexString('msgHash', msgHash);
assert.isETHAddressHex('signerAddress', signerAddress);
const web3Wrapper = new Web3Wrapper(provider);
await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper);
const normalizedSignerAddress = signerAddress.toLowerCase();
let msgHashHex = orderHash;
const prefixedMsgHashHex = signatureUtils.addSignedMessagePrefix(orderHash, signerType);
// Metamask incorrectly implements eth_sign and does not prefix the message as per the spec
// Source: https://github.com/MetaMask/metamask-extension/commit/a9d36860bec424dcee8db043d3e7da6a5ff5672e
if (signerType === SignerType.Metamask) {
msgHashHex = prefixedMsgHashHex;
}
const signature = await web3Wrapper.signMessageAsync(normalizedSignerAddress, msgHashHex);
const signature = await web3Wrapper.signMessageAsync(normalizedSignerAddress, msgHash);
const prefixedMsgHashHex = signatureUtils.addSignedMessagePrefix(msgHash);
// HACK: There is no consensus on whether the signatureHex string should be formatted as
// v + r + s OR r + s + v, and different clients (even different versions of the same client)
@ -286,10 +287,7 @@ export const signatureUtils = {
normalizedSignerAddress,
);
if (isValidRSVSignature) {
const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(
ecSignatureRSV,
signerType,
);
const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(ecSignatureRSV);
return convertedSignatureHex;
}
}
@ -301,10 +299,7 @@ export const signatureUtils = {
normalizedSignerAddress,
);
if (isValidVRSSignature) {
const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(
ecSignatureVRS,
signerType,
);
const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(ecSignatureVRS);
return convertedSignatureHex;
}
}
@ -312,30 +307,18 @@ export const signatureUtils = {
throw new Error(OrderError.InvalidSignature);
},
/**
* Combines ECSignature with V,R,S and the relevant signature type for use in 0x protocol
* Combines ECSignature with V,R,S and the EthSign signature type for use in 0x protocol
* @param ecSignature The ECSignature of the signed data
* @param signerType The SignerType of the signed data
* @return Hex encoded string of signature (v,r,s) with Signature Type
*/
convertECSignatureToSignatureHex(ecSignature: ECSignature, signerType: SignerType): string {
convertECSignatureToSignatureHex(ecSignature: ECSignature): string {
const signatureBuffer = Buffer.concat([
ethUtil.toBuffer(ecSignature.v),
ethUtil.toBuffer(ecSignature.r),
ethUtil.toBuffer(ecSignature.s),
]);
const signatureHex = `0x${signatureBuffer.toString('hex')}`;
let signatureType;
switch (signerType) {
case SignerType.Metamask:
case SignerType.Ledger:
case SignerType.Default: {
signatureType = SignatureType.EthSign;
break;
}
default:
throw new Error(`Unrecognized SignerType: ${signerType}`);
}
const signatureWithType = signatureUtils.convertToSignatureWithType(signatureHex, signatureType);
const signatureWithType = signatureUtils.convertToSignatureWithType(signatureHex, SignatureType.EthSign);
return signatureWithType;
},
/**
@ -352,28 +335,17 @@ export const signatureUtils = {
/**
* Adds the relevant prefix to the message being signed.
* @param message Message to sign
* @param signerType The type of message prefix to add for a given SignerType. Different signers expect
* specific message prefixes.
* @return Prefixed message
*/
addSignedMessagePrefix(message: string, signerType: SignerType = SignerType.Default): string {
addSignedMessagePrefix(message: string): string {
assert.isString('message', message);
assert.doesBelongToStringEnum('signerType', signerType, SignerType);
switch (signerType) {
case SignerType.Metamask:
case SignerType.Ledger:
case SignerType.Default: {
const msgBuff = ethUtil.toBuffer(message);
const prefixedMsgBuff = ethUtil.hashPersonalMessage(msgBuff);
const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
return prefixedMsgHex;
}
default:
throw new Error(`Unrecognized SignerType: ${signerType}`);
}
const msgBuff = ethUtil.toBuffer(message);
const prefixedMsgBuff = ethUtil.hashPersonalMessage(msgBuff);
const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
return prefixedMsgHex;
},
/**
* Parse a 0x protocol hex-encoded signature string into it's ECSignature components
* Parse a 0x protocol hex-encoded signature string into its ECSignature components
* @param signature A hex encoded ecSignature 0x Protocol signature
* @return An ECSignature object with r,s,v parameters
*/

View File

@ -1,4 +1,4 @@
import { Order, SignatureType, SignerType } from '@0xproject/types';
import { Order, SignatureType } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import * as chai from 'chai';
import { JSONRPCErrorCallback, JSONRPCRequestPayload } from 'ethereum-types';
@ -153,10 +153,17 @@ describe('Signature utils', () => {
]);
const signatureHex = `0x${signatureBuffer.toString('hex')}`;
const eip712Signature = await signatureUtils.ecSignOrderAsync(provider, order, makerAddress);
const isValidSignature = await signatureUtils.isValidSignatureAsync(
provider,
orderHashHex,
eip712Signature,
makerAddress,
);
expect(signatureHex).to.eq(eip712Signature);
expect(isValidSignature).to.eq(true);
});
});
describe('#ecSignOrderHashAsync', () => {
describe('#ecSignHashAsync', () => {
let makerAddress: string;
before(async () => {
const availableAddreses = await web3Wrapper.getAvailableAddressesAsync();
@ -166,12 +173,7 @@ describe('Signature utils', () => {
const orderHash = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
const expectedSignature =
'0x1b61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403';
const ecSignature = await signatureUtils.ecSignOrderHashAsync(
provider,
orderHash,
makerAddress,
SignerType.Default,
);
const ecSignature = await signatureUtils.ecSignHashAsync(provider, orderHash, makerAddress);
expect(ecSignature).to.equal(expectedSignature);
});
it('should return the correct Signature for signatureHex concatenated as R + S + V', async () => {
@ -197,12 +199,7 @@ describe('Signature utils', () => {
}
},
};
const ecSignature = await signatureUtils.ecSignOrderHashAsync(
fakeProvider,
orderHash,
makerAddress,
SignerType.Default,
);
const ecSignature = await signatureUtils.ecSignHashAsync(fakeProvider, orderHash, makerAddress);
expect(ecSignature).to.equal(expectedSignature);
});
it('should return the correct Signature for signatureHex concatenated as V + R + S', async () => {
@ -225,56 +222,12 @@ describe('Signature utils', () => {
},
};
const ecSignature = await signatureUtils.ecSignOrderHashAsync(
fakeProvider,
orderHash,
makerAddress,
SignerType.Default,
);
expect(ecSignature).to.equal(expectedSignature);
});
// Note this is due to a bug in Metamask where it does not prefix before signing, this is a known issue and is to be fixed in the future
// Source: https://github.com/MetaMask/metamask-extension/commit/a9d36860bec424dcee8db043d3e7da6a5ff5672e
it('should receive a payload modified with a prefix when Metamask is SignerType', async () => {
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
const orderHashPrefixed = '0xae70f31d26096291aa681b26cb7574563956221d0b4213631e1ef9df675d4cba';
const expectedSignature =
'0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03';
// Generated from a MM eth_sign request from 0x5409ed021d9299bf6814279a6a1411a7e866a631 signing 0xae70f31d26096291aa681b26cb7574563956221d0b4213631e1ef9df675d4cba
const metamaskSignature =
'0x117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b1b';
const fakeProvider = {
async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise<void> {
if (payload.method === 'eth_sign') {
const [, message] = payload.params;
expect(message).to.equal(orderHashPrefixed);
callback(null, {
id: 42,
jsonrpc: '2.0',
result: metamaskSignature,
});
} else {
callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] });
}
},
};
const ecSignature = await signatureUtils.ecSignOrderHashAsync(
fakeProvider,
orderHash,
makerAddress,
SignerType.Metamask,
);
const ecSignature = await signatureUtils.ecSignHashAsync(fakeProvider, orderHash, makerAddress);
expect(ecSignature).to.equal(expectedSignature);
});
it('should return a valid signature', async () => {
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
const ecSignature = await signatureUtils.ecSignOrderHashAsync(
provider,
orderHash,
makerAddress,
SignerType.Default,
);
const ecSignature = await signatureUtils.ecSignHashAsync(provider, orderHash, makerAddress);
const isValidSignature = await signatureUtils.isValidSignatureAsync(
provider,
@ -291,38 +244,11 @@ describe('Signature utils', () => {
r: '0xaca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d64393',
s: '0x46b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf2',
};
it('should concatenate v,r,s and append the EthSign signature type when SignerType is Default', async () => {
it('should concatenate v,r,s and append the EthSign signature type', async () => {
const expectedSignatureWithSignatureType =
'0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf203';
const signatureWithSignatureType = signatureUtils.convertECSignatureToSignatureHex(
ecSignature,
SignerType.Default,
);
const signatureWithSignatureType = signatureUtils.convertECSignatureToSignatureHex(ecSignature);
expect(signatureWithSignatureType).to.equal(expectedSignatureWithSignatureType);
});
it('should concatenate v,r,s and append the EthSign signature type when SignerType is Ledger', async () => {
const expectedSignatureWithSignatureType =
'0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf203';
const signatureWithSignatureType = signatureUtils.convertECSignatureToSignatureHex(
ecSignature,
SignerType.Ledger,
);
expect(signatureWithSignatureType).to.equal(expectedSignatureWithSignatureType);
});
it('should concatenate v,r,s and append the EthSign signature type when SignerType is Metamask', async () => {
const expectedSignatureWithSignatureType =
'0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf203';
const signatureWithSignatureType = signatureUtils.convertECSignatureToSignatureHex(
ecSignature,
SignerType.Metamask,
);
expect(signatureWithSignatureType).to.equal(expectedSignatureWithSignatureType);
});
it('should throw if the SignerType is invalid', async () => {
const expectedMessage = 'Unrecognized SignerType: INVALID_SIGNER';
expect(() =>
signatureUtils.convertECSignatureToSignatureHex(ecSignature, 'INVALID_SIGNER' as SignerType),
).to.throw(expectedMessage);
});
});
});

View File

@ -1,4 +1,12 @@
[
{
"version": "2.1.0",
"changes": [
{
"note": "Add Metamask Subprovider to handle inconsistent JSON RPC behaviour"
}
]
},
{
"version": "2.0.7",
"changes": [

View File

@ -27,6 +27,7 @@ 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 {

View File

@ -0,0 +1,124 @@
import { marshaller, Web3Wrapper } from '@0xproject/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 SignerSubprovider
* @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 has namespaced signTypedData to v3 for an indeterminate period of time.
// 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 });
},
);
}
}

View File

@ -23,7 +23,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')}`;
}
/**

View File

@ -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;

View File

@ -143,16 +143,6 @@ export enum SignatureType {
NSignatureTypes,
}
/**
* The type of the Signer implementation. Some signer implementations use different message prefixes or implement different
* eth_sign behaviour (e.g Metamask). Default assumes a spec compliant `eth_sign`.
*/
export enum SignerType {
Default = 'DEFAULT',
Ledger = 'LEDGER',
Metamask = 'METAMASK',
}
export enum AssetProxyId {
ERC20 = '0xf47261b0',
ERC721 = '0x02571792',

View File

@ -9,14 +9,14 @@ import {
ExchangeFillEventArgs,
IndexedFilterValues,
} from '@0xproject/contract-wrappers';
import { assetDataUtils, orderHashUtils, signatureUtils, SignerType } from '@0xproject/order-utils';
import { assetDataUtils, orderHashUtils, signatureUtils } from '@0xproject/order-utils';
import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
import {
ledgerEthereumBrowserClientFactoryAsync,
LedgerSubprovider,
MetamaskSubprovider,
RedundantSubprovider,
RPCSubprovider,
SignerSubprovider,
Web3ProviderEngine,
} from '@0xproject/subproviders';
import { SignedOrder, Token as ZeroExToken } from '@0xproject/types';
@ -161,7 +161,7 @@ export class Blockchain {
// We catch all requests involving a users account and send it to the injectedWeb3
// instance. All other requests go to the public hosted node.
const provider = new Web3ProviderEngine();
provider.addProvider(new SignerSubprovider(injectedWeb3.currentProvider));
provider.addProvider(new MetamaskSubprovider(injectedWeb3.currentProvider));
provider.addProvider(new FilterSubprovider());
const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => {
return new RPCSubprovider(publicNodeUrl);
@ -432,21 +432,7 @@ export class Blockchain {
}
this._showFlashMessageIfLedger();
const provider = this._contractWrappers.getProvider();
const isLedgerSigner = !_.isUndefined(this._ledgerSubprovider);
const injectedProvider = Blockchain._getInjectedWeb3().currentProvider;
const isMetaMaskSigner = utils.getProviderType(injectedProvider) === Providers.Metamask;
let signerType = SignerType.Default;
if (isLedgerSigner) {
signerType = SignerType.Ledger;
} else if (isMetaMaskSigner) {
signerType = SignerType.Metamask;
}
const ecSignatureString = await signatureUtils.ecSignOrderHashAsync(
provider,
orderHash,
makerAddress,
signerType,
);
const ecSignatureString = await signatureUtils.ecSignHashAsync(provider, orderHash, makerAddress);
this._dispatcher.updateSignature(ecSignatureString);
return ecSignatureString;
}

277
yarn.lock
View File

@ -1603,10 +1603,6 @@ ajv-errors@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59"
aes-js@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.1.tgz#89fd1f94ae51b4c72d62466adc1a7323ff52f072"
ajv-keywords@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
@ -1903,14 +1899,6 @@ assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
ast-types@0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd"
ast-types@0.11.3:
version "0.11.3"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8"
astral-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
@ -2258,15 +2246,7 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
babel-plugin-syntax-export-extensions@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721"
babel-plugin-syntax-flow@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0:
babel-plugin-syntax-object-rest-spread@^6.13.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
@ -2506,35 +2486,6 @@ babel-preset-env@^1.3.2:
invariant "^2.2.2"
semver "^5.3.0"
babel-preset-es2015@^6.9.0:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939"
dependencies:
babel-plugin-check-es2015-constants "^6.22.0"
babel-plugin-transform-es2015-arrow-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoping "^6.24.1"
babel-plugin-transform-es2015-classes "^6.24.1"
babel-plugin-transform-es2015-computed-properties "^6.24.1"
babel-plugin-transform-es2015-destructuring "^6.22.0"
babel-plugin-transform-es2015-duplicate-keys "^6.24.1"
babel-plugin-transform-es2015-for-of "^6.22.0"
babel-plugin-transform-es2015-function-name "^6.24.1"
babel-plugin-transform-es2015-literals "^6.22.0"
babel-plugin-transform-es2015-modules-amd "^6.24.1"
babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
babel-plugin-transform-es2015-modules-systemjs "^6.24.1"
babel-plugin-transform-es2015-modules-umd "^6.24.1"
babel-plugin-transform-es2015-object-super "^6.24.1"
babel-plugin-transform-es2015-parameters "^6.24.1"
babel-plugin-transform-es2015-shorthand-properties "^6.24.1"
babel-plugin-transform-es2015-spread "^6.22.0"
babel-plugin-transform-es2015-sticky-regex "^6.24.1"
babel-plugin-transform-es2015-template-literals "^6.22.0"
babel-plugin-transform-es2015-typeof-symbol "^6.22.0"
babel-plugin-transform-es2015-unicode-regex "^6.24.1"
babel-plugin-transform-regenerator "^6.24.1"
babel-preset-jest@^23.2.0:
version "23.2.0"
resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46"
@ -2542,34 +2493,7 @@ babel-preset-jest@^23.2.0:
babel-plugin-jest-hoist "^23.2.0"
babel-plugin-syntax-object-rest-spread "^6.13.0"
babel-preset-stage-1@^6.5.0:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0"
dependencies:
babel-plugin-transform-class-constructor-call "^6.24.1"
babel-plugin-transform-export-extensions "^6.22.0"
babel-preset-stage-2 "^6.24.1"
babel-preset-stage-2@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1"
dependencies:
babel-plugin-syntax-dynamic-import "^6.18.0"
babel-plugin-transform-class-properties "^6.24.1"
babel-plugin-transform-decorators "^6.24.1"
babel-preset-stage-3 "^6.24.1"
babel-preset-stage-3@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395"
dependencies:
babel-plugin-syntax-trailing-function-commas "^6.22.0"
babel-plugin-transform-async-generator-functions "^6.24.1"
babel-plugin-transform-async-to-generator "^6.24.1"
babel-plugin-transform-exponentiation-operator "^6.24.1"
babel-plugin-transform-object-rest-spread "^6.22.0"
babel-register@^6.26.0, babel-register@^6.9.0:
babel-register@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
dependencies:
@ -3117,14 +3041,6 @@ bser@^2.0.0:
dependencies:
node-int64 "^0.4.0"
bs58check@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
dependencies:
bs58 "^4.0.0"
create-hash "^1.1.0"
safe-buffer "^5.1.2"
btoa@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.1.2.tgz#3e40b81663f81d2dd6596a4cb714a8dc16cfabe0"
@ -3839,7 +3755,7 @@ colors@0.5.x:
version "0.5.1"
resolved "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
colors@1.0.3, colors@1.0.x:
colors@1.0.x:
version "1.0.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
@ -4240,7 +4156,7 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^6.0.0, cross-spawn@^6.0.4:
cross-spawn@^6.0.0, cross-spawn@^6.0.4, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
dependencies:
@ -5127,10 +5043,6 @@ entities@^1.1.1, entities@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
envinfo@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-4.4.2.tgz#472c49f3a8b9bca73962641ce7cb692bf623cd1c"
enzyme-adapter-react-16@^1.5.0:
version "1.5.0"
resolved "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.5.0.tgz#50af8d76a45fe0915de932bd95d34cdca75c0be3"
@ -5187,13 +5099,6 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
error@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02"
dependencies:
string-template "~0.2.1"
xtend "~4.0.0"
es-abstract@^1.10.0, es-abstract@^1.5.1, es-abstract@^1.6.1:
version "1.12.0"
resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
@ -5365,7 +5270,7 @@ esprima@^3.1.3:
version "3.1.3"
resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
esprima@^4.0.0, esprima@~4.0.0:
esprima@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
@ -6538,6 +6443,45 @@ ganache-core@0xProject/ganache-core#monorepo-dep:
merkle-patricia-tree "^2.2.0"
pify "^3.0.0"
prepend-file "^1.3.1"
seedrandom "~2.4.2"
shebang-loader "0.0.1"
solc "0.4.24"
temp "^0.8.3"
tmp "0.0.31"
web3 "^1.0.0-beta.34"
web3-provider-engine "^14.0.6"
websocket "^1.0.24"
yargs "^7.0.2"
ganache-core@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.2.1.tgz#c0125d77d3e28d627a812dd002dac21e1d2cc8b7"
dependencies:
abstract-leveldown "^3.0.0"
async "^2.5.0"
bip39 "~2.4.0"
bn.js "4.11.6"
cachedown "^1.0.0"
chai "^3.5.0"
clone "^2.1.1"
eth-sig-util "^2.0.2"
ethereumjs-abi "^0.6.5"
ethereumjs-account "~2.0.4"
ethereumjs-block "~1.2.2"
ethereumjs-tx "1.3.4"
ethereumjs-util "^5.2.0"
ethereumjs-vm "2.3.5"
ethereumjs-wallet "0.6.0"
fake-merkle-patricia-tree "~1.0.1"
heap "~0.2.6"
js-scrypt "^0.2.0"
level-sublevel "^6.6.1"
levelup "^1.1.0"
localstorage-down "^0.6.7"
lodash "^4.17.5"
merkle-patricia-tree "^2.2.0"
pify "^3.0.0"
prepend-file "^1.3.1"
request "^2.87.0"
seedrandom "~2.4.2"
shebang-loader "0.0.1"
@ -7630,17 +7574,10 @@ internal-ip@^3.0.1:
default-gateway "^2.6.0"
ipaddr.js "^1.5.2"
interpret@^1.0.0, interpret@^1.0.4, interpret@^1.1.0:
interpret@^1.0.0, interpret@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
into-stream@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6"
dependencies:
from2 "^2.1.1"
p-is-promise "^1.1.0"
invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@ -8600,46 +8537,6 @@ jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
jscodeshift@^0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.4.1.tgz#da91a1c2eccfa03a3387a21d39948e251ced444a"
dependencies:
async "^1.5.0"
babel-plugin-transform-flow-strip-types "^6.8.0"
babel-preset-es2015 "^6.9.0"
babel-preset-stage-1 "^6.5.0"
babel-register "^6.9.0"
babylon "^6.17.3"
colors "^1.1.2"
flow-parser "^0.*"
lodash "^4.13.1"
micromatch "^2.3.7"
node-dir "0.1.8"
nomnom "^1.8.1"
recast "^0.12.5"
temp "^0.8.1"
write-file-atomic "^1.2.0"
jscodeshift@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.5.0.tgz#bdb7b6cc20dd62c16aa728c3fa2d2fe66ca7c748"
dependencies:
babel-plugin-transform-flow-strip-types "^6.8.0"
babel-preset-es2015 "^6.9.0"
babel-preset-stage-1 "^6.5.0"
babel-register "^6.9.0"
babylon "^7.0.0-beta.30"
colors "^1.1.2"
flow-parser "^0.*"
lodash "^4.13.1"
micromatch "^2.3.7"
neo-async "^2.5.0"
node-dir "0.1.8"
nomnom "^1.8.1"
recast "^0.14.1"
temp "^0.8.1"
write-file-atomic "^1.2.0"
jsdom@^11.5.1:
version "11.12.0"
resolved "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8"
@ -9456,14 +9353,14 @@ lodash@^3.10.1, lodash@^3.3.1, lodash@^3.6.0, lodash@^3.7.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.13.1, lodash@^4.15.0:
version "4.17.11"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
lodash@^4.15.0:
version "4.17.11"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
lodash@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
@ -9478,7 +9375,7 @@ log-symbols@^1.0.2:
dependencies:
chalk "^1.0.0"
log-symbols@^2.2.0:
log-symbols@^2.1.0, log-symbols@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
dependencies:
@ -9599,12 +9496,6 @@ make-dir@^1.0.0:
dependencies:
pify "^3.0.0"
make-dir@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
dependencies:
pify "^3.0.0"
make-error@1.x:
version "1.3.5"
resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
@ -10439,13 +10330,6 @@ nodemon@^1.11.0:
undefsafe "^2.0.2"
update-notifier "^2.3.0"
nomnom@^1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
dependencies:
chalk "~0.4.0"
underscore "~1.6.0"
nomnom@~1.6.2:
version "1.6.2"
resolved "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971"
@ -11796,10 +11680,6 @@ pretty-bytes@^1.0.4:
get-stdin "^4.0.1"
meow "^3.1.0"
pretty-bytes@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
pretty-format@^23.6.0:
version "23.6.0"
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760"
@ -11830,7 +11710,7 @@ prismjs@^1.15.0:
optionalDependencies:
clipboard "^2.0.0"
private@^0.1.6, private@^0.1.7, private@^0.1.8, private@~0.1.5:
private@^0.1.6, private@^0.1.7, private@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
@ -12440,13 +12320,6 @@ react@^16.5.2:
prop-types "^15.6.2"
schedule "^0.5.0"
read-chunk@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655"
dependencies:
pify "^3.0.0"
safe-buffer "^5.1.1"
read-cmd-shim@^1.0.1:
version "1.0.1"
resolved "http://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b"
@ -12586,25 +12459,6 @@ realpath-native@^1.0.0:
dependencies:
util.promisify "^1.0.0"
recast@^0.12.5:
version "0.12.9"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1"
dependencies:
ast-types "0.10.1"
core-js "^2.4.1"
esprima "~4.0.0"
private "~0.1.5"
source-map "~0.6.1"
recast@^0.14.1:
version "0.14.7"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d"
dependencies:
ast-types "0.11.3"
esprima "~4.0.0"
private "~0.1.5"
source-map "~0.6.1"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@ -13169,7 +13023,7 @@ rsvp@^3.3.3:
version "3.6.2"
resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a"
run-async@^2.0.0, run-async@^2.2.0:
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
dependencies:
@ -13297,10 +13151,6 @@ schema-utils@^1.0.0:
ajv-errors "^1.0.0"
ajv-keywords "^3.1.0"
scoped-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
scrypt-async@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/scrypt-async/-/scrypt-async-1.3.1.tgz#a11fd6fac981b4b823ee01dee0221169500ddae9"
@ -14119,10 +13969,6 @@ string-length@^2.0.0:
astral-regex "^1.0.0"
strip-ansi "^4.0.0"
string-template@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@ -14186,17 +14032,6 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"
strip-ansi@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
strip-bom-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca"
dependencies:
first-chunk-stream "^2.0.0"
strip-bom "^2.0.0"
strip-bom@3.0.0, strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@ -15184,10 +15019,6 @@ underscore@~1.4.4:
version "1.4.4"
resolved "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
underscore@~1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
underscore@~1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
@ -15474,10 +15305,6 @@ uvm@1.7.0:
lodash "4.17.4"
uuid "3.0.1"
v8-compile-cache@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4"
v8-compile-cache@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c"