aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/src/signature_utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils/src/signature_utils.ts')
-rw-r--r--packages/order-utils/src/signature_utils.ts120
1 files changed, 46 insertions, 74 deletions
diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts
index 05c673ae2..8e0fd702b 100644
--- a/packages/order-utils/src/signature_utils.ts
+++ b/packages/order-utils/src/signature_utils.ts
@@ -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
*/