diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/0x.js.ts | 64 | ||||
-rw-r--r-- | src/globals.d.ts | 13 | ||||
-rw-r--r-- | src/types.ts | 1 | ||||
-rw-r--r-- | src/utils/utils.ts | 7 |
4 files changed, 82 insertions, 3 deletions
diff --git a/src/0x.js.ts b/src/0x.js.ts index de082146f..aed7513a8 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -8,9 +8,11 @@ import {Web3Wrapper} from './web3_wrapper'; import {constants} from './utils/constants'; import {utils} from './utils/utils'; import {assert} from './utils/assert'; +import findVersions = require('find-versions'); +import compareVersions = require('compare-versions'); import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper'; import {ECSignatureSchema} from './schemas/ec_signature_schema'; -import {SolidityTypes, ECSignature} from './types'; +import {SolidityTypes, ECSignature, ZeroExError} from './types'; const MAX_DIGITS_IN_UNSIGNED_256_INT = 78; @@ -131,4 +133,64 @@ export class ZeroEx { this.web3Wrapper = new Web3Wrapper(web3); this.exchange = new ExchangeWrapper(this.web3Wrapper); } + /** + * Signs an orderHash and returns it's elliptic curve signature + * This method currently supports TestRPC, Geth and Parity above and below V1.6.6 + */ + public async signOrderHashAsync(orderHashHex: string): Promise<ECSignature> { + assert.isHexString('orderHashHex', orderHashHex); + + let msgHashHex; + const nodeVersion = await this.web3Wrapper.getNodeVersionAsync(); + const isParityNode = utils.isParityNode(nodeVersion); + if (isParityNode) { + // Parity node adds the personalMessage prefix itself + msgHashHex = orderHashHex; + } else { + const orderHashBuff = ethUtil.toBuffer(orderHashHex); + const msgHashBuff = ethUtil.hashPersonalMessage(orderHashBuff); + msgHashHex = ethUtil.bufferToHex(msgHashBuff); + } + + const makerAddressIfExists = await this.web3Wrapper.getSenderAddressIfExistsAsync(); + if (_.isUndefined(makerAddressIfExists)) { + throw new Error(ZeroExError.USER_HAS_NO_ASSOCIATED_ADDRESSES); + } + + const signature = await this.web3Wrapper.signTransactionAsync(makerAddressIfExists, msgHashHex); + + let signatureData; + const [nodeVersionNumber] = findVersions(nodeVersion); + // Parity v1.6.6 and earlier returns the signatureData as vrs instead of rsv as Geth does + // Later versions return rsv but for the time being we still want to support version < 1.6.6 + // Date: May 23rd 2017 + const latestParityVersionWithVRS = '1.6.6'; + const isVersionBeforeParityFix = compareVersions(nodeVersionNumber, latestParityVersionWithVRS) <= 0; + if (isParityNode && isVersionBeforeParityFix) { + const signatureBuffer = ethUtil.toBuffer(signature); + let v = signatureBuffer[0]; + if (v < 27) { + v += 27; + } + signatureData = { + v, + r: signatureBuffer.slice(1, 33), + s: signatureBuffer.slice(33, 65), + }; + } else { + signatureData = ethUtil.fromRpcSig(signature); + } + + const {v, r, s} = signatureData; + const ecSignature: ECSignature = { + v, + r: ethUtil.bufferToHex(r), + s: ethUtil.bufferToHex(s), + }; + const isValidSignature = ZeroEx.isValidSignature(orderHashHex, ecSignature, makerAddressIfExists); + if (!isValidSignature) { + throw new Error(ZeroExError.INVALID_SIGNATURE); + } + return ecSignature; + } } diff --git a/src/globals.d.ts b/src/globals.d.ts index 0062a05cb..0f2fe0f2f 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -36,6 +36,7 @@ declare module 'ethereumjs-util' { const pubToAddress: (pubKey: string) => Buffer; const isValidAddress: (address: string) => boolean; const bufferToInt: (buffer: Buffer) => number; + const fromRpcSig: (signature: string) => {v: number, r: Buffer, s: Buffer}; } // truffle-contract declarations @@ -53,6 +54,18 @@ declare module 'truffle-contract' { export = contract; } +// find-version declarations +declare function findVersions(version: string): string[]; +declare module 'find-versions' { + export = findVersions; +} + +// compare-version declarations +declare function compareVersions(firstVersion: string, secondVersion: string): number; +declare module 'compare-versions' { + export = compareVersions; +} + // es6-promisify declarations declare function promisify(original: any, settings?: any): ((...arg: any[]) => Promise<any>); declare module 'es6-promisify' { diff --git a/src/types.ts b/src/types.ts index 4da03a4d3..3bed01547 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,6 +13,7 @@ export const ZeroExError = strEnum([ 'CONTRACT_DOES_NOT_EXIST', 'UNHANDLED_ERROR', 'USER_HAS_NO_ASSOCIATED_ADDRESSES', + 'INVALID_SIGNATURE', ]); export type ZeroExError = keyof typeof ZeroExError; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index b514b702d..336eaf7bb 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,3 +1,4 @@ +import * as _ from 'lodash'; import * as BN from 'bn.js'; export const utils = { @@ -11,8 +12,10 @@ export const utils = { return new BN(value.toString(), 10); }, consoleLog(message: string): void { - /* tslint:disable */ + // tslint:disable-next-line: no-console console.log(message); - /* tslint:enable */ + }, + isParityNode(nodeVersion: string): boolean { + return _.includes(nodeVersion, 'Parity'); }, }; |