diff options
Diffstat (limited to 'packages/order-utils/src/signature_utils.ts')
-rw-r--r-- | packages/order-utils/src/signature_utils.ts | 626 |
1 files changed, 325 insertions, 301 deletions
diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 870aef2ed..40bbcef98 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -13,329 +13,353 @@ import { IWalletContract } from './generated_contract_wrappers/i_wallet'; import { OrderError } from './types'; import { utils } from './utils'; -/** - * Verifies that the provided signature is valid according to the 0x Protocol smart contracts - * @param data The hex encoded data signed by the supplied signature. - * @param signature A hex encoded 0x Protocol signature made up of: [TypeSpecificData][SignatureType]. - * E.g [vrs][SignatureType.EIP712] - * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. - * @return Whether the signature is valid for the supplied signerAddress and data. - */ -export async function isValidSignatureAsync( - provider: Provider, - data: string, - signature: string, - signerAddress: string, -): Promise<boolean> { - assert.isWeb3Provider('provider', provider); - assert.isHexString('data', data); - assert.isHexString('signature', signature); - assert.isETHAddressHex('signerAddress', signerAddress); - const signatureTypeIndexIfExists = utils.getSignatureTypeIndexIfExists(signature); - if (_.isUndefined(signatureTypeIndexIfExists)) { - throw new Error(`Unrecognized signatureType in signature: ${signature}`); - } - - switch (signatureTypeIndexIfExists) { - case SignatureType.Illegal: - case SignatureType.Invalid: - return false; - - case SignatureType.EIP712: { - const ecSignature = parseECSignature(signature); - return isValidECSignature(data, ecSignature, signerAddress); +export const signatureUtils = { + /** + * Verifies that the provided signature is valid according to the 0x Protocol smart contracts + * @param data The hex encoded data signed by the supplied signature. + * @param signature A hex encoded 0x Protocol signature made up of: [TypeSpecificData][SignatureType]. + * E.g [vrs][SignatureType.EIP712] + * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. + * @return Whether the signature is valid for the supplied signerAddress and data. + */ + async isValidSignatureAsync( + provider: Provider, + data: string, + signature: string, + signerAddress: string, + ): Promise<boolean> { + assert.isWeb3Provider('provider', provider); + assert.isHexString('data', data); + assert.isHexString('signature', signature); + assert.isETHAddressHex('signerAddress', signerAddress); + const signatureTypeIndexIfExists = utils.getSignatureTypeIndexIfExists(signature); + if (_.isUndefined(signatureTypeIndexIfExists)) { + throw new Error(`Unrecognized signatureType in signature: ${signature}`); } - case SignatureType.EthSign: { - const ecSignature = parseECSignature(signature); - const prefixedMessageHex = addSignedMessagePrefix(data, SignerType.Default); - return isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); - } + switch (signatureTypeIndexIfExists) { + case SignatureType.Illegal: + case SignatureType.Invalid: + return false; - case SignatureType.Caller: - // HACK: We currently do not "validate" the caller signature type. - // It can only be validated during Exchange contract execution. - throw new Error('Caller signature type cannot be validated off-chain'); + case SignatureType.EIP712: { + const ecSignature = signatureUtils.parseECSignature(signature); + return signatureUtils.isValidECSignature(data, ecSignature, signerAddress); + } - case SignatureType.Wallet: { - const isValid = await isValidWalletSignatureAsync(provider, data, signature, signerAddress); - return isValid; - } + case SignatureType.EthSign: { + const ecSignature = signatureUtils.parseECSignature(signature); + const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, SignerType.Default); + return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); + } - case SignatureType.Validator: { - const isValid = await isValidValidatorSignatureAsync(provider, data, signature, signerAddress); - return isValid; - } + case SignatureType.Caller: + // HACK: We currently do not "validate" the caller signature type. + // It can only be validated during Exchange contract execution. + throw new Error('Caller signature type cannot be validated off-chain'); - case SignatureType.PreSigned: { - return isValidPresignedSignatureAsync(provider, data, signerAddress); - } + case SignatureType.Wallet: { + const isValid = await signatureUtils.isValidWalletSignatureAsync( + provider, + data, + signature, + signerAddress, + ); + return isValid; + } - case SignatureType.Trezor: { - const prefixedMessageHex = addSignedMessagePrefix(data, SignerType.Trezor); - const ecSignature = parseECSignature(signature); - return isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); - } + case SignatureType.Validator: { + const isValid = await signatureUtils.isValidValidatorSignatureAsync( + provider, + data, + signature, + signerAddress, + ); + return isValid; + } - default: - throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`); - } -} + case SignatureType.PreSigned: { + return signatureUtils.isValidPresignedSignatureAsync(provider, data, signerAddress); + } -/** - * Verifies that the provided presigned signature is valid according to the 0x Protocol smart contracts - * @param data The hex encoded data signed by the supplied signature. - * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned] - * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. - * @return Whether the data was preSigned by the supplied signerAddress. - */ -export async function isValidPresignedSignatureAsync( - provider: Provider, - data: string, - signerAddress: string, -): Promise<boolean> { - assert.isWeb3Provider('provider', provider); - assert.isHexString('data', data); - assert.isETHAddressHex('signerAddress', signerAddress); - const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider); - const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress); - return isValid; -} - -/** - * Verifies that the provided wallet signature is valid according to the 0x Protocol smart contracts - * @param data The hex encoded data signed by the supplied signature. - * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned] - * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. - * @return Whether the data was preSigned by the supplied signerAddress. - */ -export async function isValidWalletSignatureAsync( - provider: Provider, - data: string, - signature: string, - signerAddress: string, -): Promise<boolean> { - assert.isWeb3Provider('provider', provider); - assert.isHexString('data', data); - assert.isHexString('signature', signature); - assert.isETHAddressHex('signerAddress', signerAddress); - // tslint:disable-next-line:custom-no-magic-numbers - const signatureWithoutType = signature.slice(-2); - const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider); - const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType); - return isValid; -} - -/** - * Verifies that the provided validator signature is valid according to the 0x Protocol smart contracts - * @param data The hex encoded data signed by the supplied signature. - * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned] - * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. - * @return Whether the data was preSigned by the supplied signerAddress. - */ -export async function isValidValidatorSignatureAsync( - provider: Provider, - data: string, - signature: string, - signerAddress: string, -): Promise<boolean> { - assert.isWeb3Provider('provider', provider); - assert.isHexString('data', data); - assert.isHexString('signature', signature); - assert.isETHAddressHex('signerAddress', signerAddress); - const validatorSignature = parseValidatorSignature(signature); - const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider); - const isValidatorApproved = await exchangeContract.allowedValidators.callAsync( - signerAddress, - validatorSignature.validatorAddress, - ); - if (!isValidatorApproved) { - throw new Error(`Validator ${validatorSignature.validatorAddress} was not pre-approved by ${signerAddress}.`); - } + case SignatureType.Trezor: { + const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, SignerType.Trezor); + const ecSignature = signatureUtils.parseECSignature(signature); + return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); + } - const validatorContract = new IValidatorContract(artifacts.IValidator.compilerOutput.abi, signerAddress, provider); - const isValid = await validatorContract.isValidSignature.callAsync( - data, - signerAddress, - validatorSignature.signature, - ); - return isValid; -} - -/** - * Checks if the supplied elliptic curve signature corresponds to signing `data` with - * the private key corresponding to `signerAddress` - * @param data The hex encoded data signed by the supplied signature. - * @param signature An object containing the elliptic curve signature parameters. - * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. - * @return Whether the ECSignature is valid. - */ -export function isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean { - assert.isHexString('data', data); - assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema); - assert.isETHAddressHex('signerAddress', signerAddress); - - const msgHashBuff = ethUtil.toBuffer(data); - try { - const pubKey = ethUtil.ecrecover( - msgHashBuff, - signature.v, - ethUtil.toBuffer(signature.r), - ethUtil.toBuffer(signature.s), + default: + throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`); + } + }, + /** + * Verifies that the provided presigned signature is valid according to the 0x Protocol smart contracts + * @param provider Web3 provider to use for all JSON RPC requests + * @param data The hex encoded data signed by the supplied signature + * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. + * @return Whether the data was preSigned by the supplied signerAddress + */ + async isValidPresignedSignatureAsync(provider: Provider, data: string, signerAddress: string): Promise<boolean> { + assert.isWeb3Provider('provider', provider); + assert.isHexString('data', data); + assert.isETHAddressHex('signerAddress', signerAddress); + const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider); + const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress); + return isValid; + }, + /** + * Verifies that the provided wallet signature is valid according to the 0x Protocol smart contracts + * @param provider Web3 provider to use for all JSON RPC requests + * @param data The hex encoded data signed by the supplied signature. + * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned] + * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. + * @return Whether the data was preSigned by the supplied signerAddress. + */ + async isValidWalletSignatureAsync( + provider: Provider, + data: string, + signature: string, + signerAddress: string, + ): Promise<boolean> { + assert.isWeb3Provider('provider', provider); + assert.isHexString('data', data); + assert.isHexString('signature', signature); + assert.isETHAddressHex('signerAddress', signerAddress); + // tslint:disable-next-line:custom-no-magic-numbers + const signatureWithoutType = signature.slice(-2); + const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider); + const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType); + return isValid; + }, + /** + * Verifies that the provided validator signature is valid according to the 0x Protocol smart contracts + * @param provider Web3 provider to use for all JSON RPC requests + * @param data The hex encoded data signed by the supplied signature. + * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned] + * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. + * @return Whether the data was preSigned by the supplied signerAddress. + */ + async isValidValidatorSignatureAsync( + provider: Provider, + data: string, + signature: string, + signerAddress: string, + ): Promise<boolean> { + assert.isWeb3Provider('provider', provider); + assert.isHexString('data', data); + assert.isHexString('signature', signature); + assert.isETHAddressHex('signerAddress', signerAddress); + const validatorSignature = parseValidatorSignature(signature); + const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider); + const isValidatorApproved = await exchangeContract.allowedValidators.callAsync( + signerAddress, + validatorSignature.validatorAddress, ); - const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); - return retrievedAddress === signerAddress; - } catch (err) { - return false; - } -} - -/** - * Signs an orderHash and returns it's 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 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. - */ -export async function ecSignOrderHashAsync( - provider: Provider, - orderHash: string, - signerAddress: string, - signerType: SignerType, -): Promise<string> { - assert.isWeb3Provider('provider', provider); - assert.isHexString('orderHash', orderHash); - assert.isETHAddressHex('signerAddress', signerAddress); - const web3Wrapper = new Web3Wrapper(provider); - await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper); - const normalizedSignerAddress = signerAddress.toLowerCase(); + if (!isValidatorApproved) { + throw new Error( + `Validator ${validatorSignature.validatorAddress} was not pre-approved by ${signerAddress}.`, + ); + } - let msgHashHex = orderHash; - const prefixedMsgHashHex = 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 validatorContract = new IValidatorContract( + artifacts.IValidator.compilerOutput.abi, + signerAddress, + provider, + ); + const isValid = await validatorContract.isValidSignature.callAsync( + data, + signerAddress, + validatorSignature.signature, + ); + return isValid; + }, + /** + * Checks if the supplied elliptic curve signature corresponds to signing `data` with + * the private key corresponding to `signerAddress` + * @param data The hex encoded data signed by the supplied signature. + * @param signature An object containing the elliptic curve signature parameters. + * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. + * @return Whether the ECSignature is valid. + */ + isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean { + assert.isHexString('data', data); + assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema); + assert.isETHAddressHex('signerAddress', signerAddress); - // 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) - // return the signature params in different orders. In order to support all client implementations, - // we parse the signature in both ways, and evaluate if either one is a valid signature. - // r + s + v is the most prevalent format from eth_sign, so we attempt this first. - // tslint:disable-next-line:custom-no-magic-numbers - const validVParamValues = [27, 28]; - const ecSignatureRSV = parseSignatureHexAsRSV(signature); - if (_.includes(validVParamValues, ecSignatureRSV.v)) { - const isValidRSVSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureRSV, normalizedSignerAddress); - if (isValidRSVSignature) { - const convertedSignatureHex = convertECSignatureToSignatureHex(ecSignatureRSV, signerType); - return convertedSignatureHex; + const msgHashBuff = ethUtil.toBuffer(data); + try { + const pubKey = ethUtil.ecrecover( + msgHashBuff, + signature.v, + ethUtil.toBuffer(signature.r), + ethUtil.toBuffer(signature.s), + ); + const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); + return retrievedAddress === signerAddress; + } catch (err) { + return false; } - } - const ecSignatureVRS = parseSignatureHexAsVRS(signature); - if (_.includes(validVParamValues, ecSignatureVRS.v)) { - const isValidVRSSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureVRS, normalizedSignerAddress); - if (isValidVRSSignature) { - const convertedSignatureHex = convertECSignatureToSignatureHex(ecSignatureVRS, signerType); - return convertedSignatureHex; + }, + /** + * Signs an orderHash and returns it's 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 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. + */ + async ecSignOrderHashAsync( + provider: Provider, + orderHash: string, + signerAddress: string, + signerType: SignerType, + ): Promise<string> { + assert.isWeb3Provider('provider', provider); + assert.isHexString('orderHash', orderHash); + 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); - throw new Error(OrderError.InvalidSignature); -} -/** - * Combines ECSignature with V,R,S and the relevant 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 - */ -export function convertECSignatureToSignatureHex(ecSignature: ECSignature, signerType: SignerType): 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; + // 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) + // return the signature params in different orders. In order to support all client implementations, + // we parse the signature in both ways, and evaluate if either one is a valid signature. + // r + s + v is the most prevalent format from eth_sign, so we attempt this first. + // tslint:disable-next-line:custom-no-magic-numbers + const validVParamValues = [27, 28]; + const ecSignatureRSV = parseSignatureHexAsRSV(signature); + if (_.includes(validVParamValues, ecSignatureRSV.v)) { + const isValidRSVSignature = signatureUtils.isValidECSignature( + prefixedMsgHashHex, + ecSignatureRSV, + normalizedSignerAddress, + ); + if (isValidRSVSignature) { + const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex( + ecSignatureRSV, + signerType, + ); + return convertedSignatureHex; + } } - case SignerType.Trezor: { - signatureType = SignatureType.Trezor; - break; + const ecSignatureVRS = parseSignatureHexAsVRS(signature); + if (_.includes(validVParamValues, ecSignatureVRS.v)) { + const isValidVRSSignature = signatureUtils.isValidECSignature( + prefixedMsgHashHex, + ecSignatureVRS, + normalizedSignerAddress, + ); + if (isValidVRSSignature) { + const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex( + ecSignatureVRS, + signerType, + ); + return convertedSignatureHex; + } } - default: - throw new Error(`Unrecognized SignerType: ${signerType}`); - } - const signatureWithType = convertToSignatureWithType(signatureHex, signatureType); - return signatureWithType; -} -/** - * Combines the signature proof and the Signature Type. - * @param signature The hex encoded signature proof - * @param signatureType The signature type, i.e EthSign, Trezor, Wallet etc. - * @return Hex encoded string of signature proof with Signature Type - */ -export function convertToSignatureWithType(signature: string, signatureType: SignatureType): string { - const signatureBuffer = Buffer.concat([ethUtil.toBuffer(signature), ethUtil.toBuffer(signatureType)]); - const signatureHex = `0x${signatureBuffer.toString('hex')}`; - return signatureHex; -} -/** - * 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 - */ -export function addSignedMessagePrefix(message: string, signerType: SignerType = SignerType.Default): 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; + + throw new Error(OrderError.InvalidSignature); + }, + /** + * Combines ECSignature with V,R,S and the relevant 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 { + 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; + } + case SignerType.Trezor: { + signatureType = SignatureType.Trezor; + break; + } + default: + throw new Error(`Unrecognized SignerType: ${signerType}`); } - case SignerType.Trezor: { - const msgBuff = ethUtil.toBuffer(message); - const prefixedMsgBuff = hashTrezorPersonalMessage(msgBuff); - const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff); - return prefixedMsgHex; + const signatureWithType = signatureUtils.convertToSignatureWithType(signatureHex, signatureType); + return signatureWithType; + }, + /** + * Combines the signature proof and the Signature Type. + * @param signature The hex encoded signature proof + * @param signatureType The signature type, i.e EthSign, Trezor, Wallet etc. + * @return Hex encoded string of signature proof with Signature Type + */ + convertToSignatureWithType(signature: string, signatureType: SignatureType): string { + const signatureBuffer = Buffer.concat([ethUtil.toBuffer(signature), ethUtil.toBuffer(signatureType)]); + const signatureHex = `0x${signatureBuffer.toString('hex')}`; + return signatureHex; + }, + /** + * 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 { + 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; + } + case SignerType.Trezor: { + const msgBuff = ethUtil.toBuffer(message); + const prefixedMsgBuff = hashTrezorPersonalMessage(msgBuff); + const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff); + return prefixedMsgHex; + } + default: + throw new Error(`Unrecognized SignerType: ${signerType}`); } - default: - throw new Error(`Unrecognized SignerType: ${signerType}`); - } -} - -/** - * Parse a 0x protocol hex-encoded signature string into it's ECSignature components - * @param signature A hex encoded ecSignature 0x Protocol signature - * @return An ECSignature object with r,s,v parameters - */ -export function parseECSignature(signature: string): ECSignature { - assert.isHexString('signature', signature); - const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor]; - assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes); + }, + /** + * Parse a 0x protocol hex-encoded signature string into it's ECSignature components + * @param signature A hex encoded ecSignature 0x Protocol signature + * @return An ECSignature object with r,s,v parameters + */ + parseECSignature(signature: string): ECSignature { + assert.isHexString('signature', signature); + const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor]; + assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes); - // tslint:disable-next-line:custom-no-magic-numbers - const vrsHex = signature.slice(0, -2); - const ecSignature = parseSignatureHexAsVRS(vrsHex); + // tslint:disable-next-line:custom-no-magic-numbers + const vrsHex = signature.slice(0, -2); + const ecSignature = parseSignatureHexAsVRS(vrsHex); - return ecSignature; -} + return ecSignature; + }, +}; function hashTrezorPersonalMessage(message: Buffer): Buffer { const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.byteLength)); |