Make signature_util into an object literal so related functions are rendered together in the docs

This commit is contained in:
Fabio Berger
2018-08-03 17:15:14 +02:00
parent 0d3d9dad84
commit d85ce6ac75
10 changed files with 379 additions and 317 deletions

View File

@@ -11,9 +11,8 @@ import {
} from '@0xproject/contract-wrappers'; } from '@0xproject/contract-wrappers';
import { import {
assetDataUtils, assetDataUtils,
ecSignOrderHashAsync,
generatePseudoRandomSalt, generatePseudoRandomSalt,
isValidSignatureAsync, signatureUtils,
MessagePrefixOpts, MessagePrefixOpts,
orderHashUtils, orderHashUtils,
} from '@0xproject/order-utils'; } from '@0xproject/order-utils';
@@ -198,7 +197,7 @@ export class ZeroEx {
* @return Whether the signature is valid for the supplied signerAddress and data. * @return Whether the signature is valid for the supplied signerAddress and data.
*/ */
public async isValidSignatureAsync(data: string, signature: string, signerAddress: string): Promise<boolean> { public async isValidSignatureAsync(data: string, signature: string, signerAddress: string): Promise<boolean> {
const isValid = await isValidSignatureAsync( const isValid = await signatureUtils.isValidSignatureAsync(
this._contractWrappers.getProvider(), this._contractWrappers.getProvider(),
data, data,
signature, signature,
@@ -238,7 +237,7 @@ export class ZeroEx {
* @param orderHash Hex encoded orderHash to sign. * @param orderHash Hex encoded orderHash to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address * @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. * must be available via the Provider supplied to 0x.js.
* @param MessagePrefixOpts Options regarding the desired prefix and whether to add it before calling `eth_sign` * @param messagePrefixOpts Options regarding the desired prefix and whether to add it before calling `eth_sign`
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash. * @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
*/ */
public async ecSignOrderHashAsync( public async ecSignOrderHashAsync(
@@ -246,7 +245,7 @@ export class ZeroEx {
signerAddress: string, signerAddress: string,
messagePrefixOpts: MessagePrefixOpts, messagePrefixOpts: MessagePrefixOpts,
): Promise<ECSignature> { ): Promise<ECSignature> {
const signature = await ecSignOrderHashAsync( const signature = await signatureUtils.ecSignOrderHashAsync(
this._contractWrappers.getProvider(), this._contractWrappers.getProvider(),
orderHash, orderHash,
signerAddress, signerAddress,

View File

@@ -1,7 +1,7 @@
import { assert as sharedAssert } from '@0xproject/assert'; import { assert as sharedAssert } from '@0xproject/assert';
// HACK: We need those two unused imports because they're actually used by sharedAssert which gets injected here // HACK: We need those two unused imports because they're actually used by sharedAssert which gets injected here
import { Schema } from '@0xproject/json-schemas'; // tslint:disable-line:no-unused-variable import { Schema } from '@0xproject/json-schemas'; // tslint:disable-line:no-unused-variable
import { isValidSignatureAsync } from '@0xproject/order-utils'; import { signatureUtils } from '@0xproject/order-utils';
import { ECSignature } from '@0xproject/types'; // tslint:disable-line:no-unused-variable import { ECSignature } from '@0xproject/types'; // tslint:disable-line:no-unused-variable
import { BigNumber } from '@0xproject/utils'; // tslint:disable-line:no-unused-variable import { BigNumber } from '@0xproject/utils'; // tslint:disable-line:no-unused-variable
import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Web3Wrapper } from '@0xproject/web3-wrapper';
@@ -15,7 +15,7 @@ export const assert = {
signature: string, signature: string,
signerAddress: string, signerAddress: string,
): Promise<void> { ): Promise<void> {
const isValid = await isValidSignatureAsync(provider, orderHash, signature, signerAddress); const isValid = await signatureUtils.isValidSignatureAsync(provider, orderHash, signature, signerAddress);
this.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`); this.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
}, },
isValidSubscriptionToken(variableName: string, subscriptionToken: string): void { isValidSubscriptionToken(variableName: string, subscriptionToken: string): void {

View File

@@ -1,5 +1,5 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { addSignedMessagePrefix, assetDataUtils, MessagePrefixType, orderHashUtils } from '@0xproject/order-utils'; import { signatureUtils, assetDataUtils, MessagePrefixType, orderHashUtils } from '@0xproject/order-utils';
import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types'; import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types';
import * as chai from 'chai'; import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types'; import { LogWithDecodedArgs } from 'ethereum-types';
@@ -213,7 +213,10 @@ describe('MixinSignatureValidator', () => {
it('should return true when SignatureType=EthSign and signature is valid', async () => { it('should return true when SignatureType=EthSign and signature is valid', async () => {
// Create EthSign signature // Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.EthSign); const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
MessagePrefixType.EthSign,
);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex); const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey); const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature // Create 0x signature from EthSign signature
@@ -236,7 +239,10 @@ describe('MixinSignatureValidator', () => {
it('should return false when SignatureType=EthSign and signature is invalid', async () => { it('should return false when SignatureType=EthSign and signature is invalid', async () => {
// Create EthSign signature // Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.EthSign); const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
MessagePrefixType.EthSign,
);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex); const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey); const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature // Create 0x signature from EthSign signature
@@ -385,7 +391,10 @@ describe('MixinSignatureValidator', () => {
it('should return true when SignatureType=Trezor and signature is valid', async () => { it('should return true when SignatureType=Trezor and signature is valid', async () => {
// Create Trezor signature // Create Trezor signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.Trezor); const orderHashWithTrezorPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
MessagePrefixType.Trezor,
);
const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex); const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey); const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey);
// Create 0x signature from Trezor signature // Create 0x signature from Trezor signature
@@ -408,7 +417,10 @@ describe('MixinSignatureValidator', () => {
it('should return false when SignatureType=Trezor and signature is invalid', async () => { it('should return false when SignatureType=Trezor and signature is invalid', async () => {
// Create Trezor signature // Create Trezor signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.Trezor); const orderHashWithTrezorPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
MessagePrefixType.Trezor,
);
const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex); const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey); const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey);
// Create 0x signature from Trezor signature // Create 0x signature from Trezor signature

View File

@@ -1,4 +1,5 @@
import { assetDataUtils, orderFactory } from '@0xproject/order-utils'; import { assetDataUtils } from '@0xproject/order-utils';
import { orderFactory } from '@0xproject/order-utils/lib/src/order_factory';
import { AssetProxyId, ERC721AssetData, OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types'; import { AssetProxyId, ERC721AssetData, OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Web3Wrapper } from '@0xproject/web3-wrapper';

View File

@@ -1,15 +1,5 @@
export { orderHashUtils } from './order_hash'; export { orderHashUtils } from './order_hash';
export { export { signatureUtils } from './signature_utils';
isValidSignatureAsync,
isValidPresignedSignatureAsync,
isValidWalletSignatureAsync,
isValidValidatorSignatureAsync,
isValidECSignature,
ecSignOrderHashAsync,
addSignedMessagePrefix,
parseECSignature,
} from './signature_utils';
export { orderFactory } from './order_factory';
export { constants } from './constants'; export { constants } from './constants';
export { crypto } from './crypto'; export { crypto } from './crypto';
export { generatePseudoRandomSalt } from './salt'; export { generatePseudoRandomSalt } from './salt';

View File

@@ -6,7 +6,7 @@ import * as _ from 'lodash';
import { orderHashUtils } from './order_hash'; import { orderHashUtils } from './order_hash';
import { generatePseudoRandomSalt } from './salt'; import { generatePseudoRandomSalt } from './salt';
import { ecSignOrderHashAsync } from './signature_utils'; import { signatureUtils } from './signature_utils';
import { MessagePrefixType } from './types'; import { MessagePrefixType } from './types';
export const orderFactory = { export const orderFactory = {
@@ -49,7 +49,12 @@ export const orderFactory = {
prefixType: MessagePrefixType.EthSign, prefixType: MessagePrefixType.EthSign,
shouldAddPrefixBeforeCallingEthSign: false, shouldAddPrefixBeforeCallingEthSign: false,
}; };
const ecSignature = await ecSignOrderHashAsync(provider, orderHash, makerAddress, messagePrefixOpts); const ecSignature = await signatureUtils.ecSignOrderHashAsync(
provider,
orderHash,
makerAddress,
messagePrefixOpts,
);
const signature = getVRSHexString(ecSignature); const signature = getVRSHexString(ecSignature);
const signedOrder: SignedOrder = _.assign(order, { signature }); const signedOrder: SignedOrder = _.assign(order, { signature });
return signedOrder; return signedOrder;

View File

@@ -9,7 +9,7 @@ import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_f
import { constants } from './constants'; import { constants } from './constants';
import { ExchangeTransferSimulator } from './exchange_transfer_simulator'; import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
import { orderHashUtils } from './order_hash'; import { orderHashUtils } from './order_hash';
import { isValidSignatureAsync } from './signature_utils'; import { signatureUtils } from './signature_utils';
import { utils } from './utils'; import { utils } from './utils';
export class OrderValidationUtils { export class OrderValidationUtils {
@@ -147,7 +147,7 @@ export class OrderValidationUtils {
throw new Error(RevertReason.InvalidTakerAmount); throw new Error(RevertReason.InvalidTakerAmount);
} }
const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const isValid = await isValidSignatureAsync( const isValid = await signatureUtils.isValidSignatureAsync(
provider, provider,
orderHash, orderHash,
signedOrder.signature, signedOrder.signature,

View File

@@ -13,20 +13,22 @@ import { IWalletContract } from './generated_contract_wrappers/i_wallet';
import { MessagePrefixOpts, MessagePrefixType, OrderError } from './types'; import { MessagePrefixOpts, MessagePrefixType, OrderError } from './types';
import { utils } from './utils'; import { utils } from './utils';
/** export const signatureUtils = {
/**
* Verifies that the provided signature is valid according to the 0x Protocol smart contracts * Verifies that the provided 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 data The hex encoded data signed by the supplied signature.
* @param signature A hex encoded 0x Protocol signature made up of: [TypeSpecificData][SignatureType]. * @param signature A hex encoded 0x Protocol signature made up of: [TypeSpecificData][SignatureType].
* E.g [vrs][SignatureType.EIP712] * E.g [vrs][SignatureType.EIP712]
* @param signerAddress The hex encoded address that signed the data, producing the supplied signature. * @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. * @return Whether the signature is valid for the supplied signerAddress and data.
*/ */
export async function isValidSignatureAsync( async isValidSignatureAsync(
provider: Provider, provider: Provider,
data: string, data: string,
signature: string, signature: string,
signerAddress: string, signerAddress: string,
): Promise<boolean> { ): Promise<boolean> {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isHexString('data', data); assert.isHexString('data', data);
assert.isHexString('signature', signature); assert.isHexString('signature', signature);
@@ -42,14 +44,14 @@ export async function isValidSignatureAsync(
return false; return false;
case SignatureType.EIP712: { case SignatureType.EIP712: {
const ecSignature = parseECSignature(signature); const ecSignature = signatureUtils.parseECSignature(signature);
return isValidECSignature(data, ecSignature, signerAddress); return signatureUtils.isValidECSignature(data, ecSignature, signerAddress);
} }
case SignatureType.EthSign: { case SignatureType.EthSign: {
const ecSignature = parseECSignature(signature); const ecSignature = signatureUtils.parseECSignature(signature);
const prefixedMessageHex = addSignedMessagePrefix(data, MessagePrefixType.EthSign); const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, MessagePrefixType.EthSign);
return isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
} }
case SignatureType.Caller: case SignatureType.Caller:
@@ -58,63 +60,68 @@ export async function isValidSignatureAsync(
throw new Error('Caller signature type cannot be validated off-chain'); throw new Error('Caller signature type cannot be validated off-chain');
case SignatureType.Wallet: { case SignatureType.Wallet: {
const isValid = await isValidWalletSignatureAsync(provider, data, signature, signerAddress); const isValid = await signatureUtils.isValidWalletSignatureAsync(
provider,
data,
signature,
signerAddress,
);
return isValid; return isValid;
} }
case SignatureType.Validator: { case SignatureType.Validator: {
const isValid = await isValidValidatorSignatureAsync(provider, data, signature, signerAddress); const isValid = await signatureUtils.isValidValidatorSignatureAsync(
provider,
data,
signature,
signerAddress,
);
return isValid; return isValid;
} }
case SignatureType.PreSigned: { case SignatureType.PreSigned: {
return isValidPresignedSignatureAsync(provider, data, signerAddress); return signatureUtils.isValidPresignedSignatureAsync(provider, data, signerAddress);
} }
case SignatureType.Trezor: { case SignatureType.Trezor: {
const prefixedMessageHex = addSignedMessagePrefix(data, MessagePrefixType.Trezor); const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, MessagePrefixType.Trezor);
const ecSignature = parseECSignature(signature); const ecSignature = signatureUtils.parseECSignature(signature);
return isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
} }
default: default:
throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`); throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`);
} }
} },
/**
/**
* Verifies that the provided presigned signature is valid according to the 0x Protocol smart contracts * 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 provider Web3 provider to use for all JSON RPC requests
* @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned] * @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. * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
* @return Whether the data was preSigned by the supplied signerAddress. * @return Whether the data was preSigned by the supplied signerAddress
*/ */
export async function isValidPresignedSignatureAsync( async isValidPresignedSignatureAsync(provider: Provider, data: string, signerAddress: string): Promise<boolean> {
provider: Provider,
data: string,
signerAddress: string,
): Promise<boolean> {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isHexString('data', data); assert.isHexString('data', data);
assert.isETHAddressHex('signerAddress', signerAddress); assert.isETHAddressHex('signerAddress', signerAddress);
const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider); const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider);
const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress); const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress);
return isValid; return isValid;
} },
/**
/**
* Verifies that the provided wallet signature is valid according to the 0x Protocol smart contracts * 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 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 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. * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
* @return Whether the data was preSigned by the supplied signerAddress. * @return Whether the data was preSigned by the supplied signerAddress.
*/ */
export async function isValidWalletSignatureAsync( async isValidWalletSignatureAsync(
provider: Provider, provider: Provider,
data: string, data: string,
signature: string, signature: string,
signerAddress: string, signerAddress: string,
): Promise<boolean> { ): Promise<boolean> {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isHexString('data', data); assert.isHexString('data', data);
assert.isHexString('signature', signature); assert.isHexString('signature', signature);
@@ -124,21 +131,21 @@ export async function isValidWalletSignatureAsync(
const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider); const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider);
const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType); const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType);
return isValid; return isValid;
} },
/**
/**
* Verifies that the provided validator signature is valid according to the 0x Protocol smart contracts * 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 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 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. * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
* @return Whether the data was preSigned by the supplied signerAddress. * @return Whether the data was preSigned by the supplied signerAddress.
*/ */
export async function isValidValidatorSignatureAsync( async isValidValidatorSignatureAsync(
provider: Provider, provider: Provider,
data: string, data: string,
signature: string, signature: string,
signerAddress: string, signerAddress: string,
): Promise<boolean> { ): Promise<boolean> {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isHexString('data', data); assert.isHexString('data', data);
assert.isHexString('signature', signature); assert.isHexString('signature', signature);
@@ -150,19 +157,24 @@ export async function isValidValidatorSignatureAsync(
validatorSignature.validatorAddress, validatorSignature.validatorAddress,
); );
if (!isValidatorApproved) { if (!isValidatorApproved) {
throw new Error(`Validator ${validatorSignature.validatorAddress} was not pre-approved by ${signerAddress}.`); throw new Error(
`Validator ${validatorSignature.validatorAddress} was not pre-approved by ${signerAddress}.`,
);
} }
const validatorContract = new IValidatorContract(artifacts.IValidator.compilerOutput.abi, signerAddress, provider); const validatorContract = new IValidatorContract(
artifacts.IValidator.compilerOutput.abi,
signerAddress,
provider,
);
const isValid = await validatorContract.isValidSignature.callAsync( const isValid = await validatorContract.isValidSignature.callAsync(
data, data,
signerAddress, signerAddress,
validatorSignature.signature, validatorSignature.signature,
); );
return isValid; return isValid;
} },
/**
/**
* Checks if the supplied elliptic curve signature corresponds to signing `data` with * Checks if the supplied elliptic curve signature corresponds to signing `data` with
* the private key corresponding to `signerAddress` * the private key corresponding to `signerAddress`
* @param data The hex encoded data signed by the supplied signature. * @param data The hex encoded data signed by the supplied signature.
@@ -170,7 +182,7 @@ export async function isValidValidatorSignatureAsync(
* @param signerAddress The hex encoded address that signed the data, producing the supplied signature. * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
* @return Whether the ECSignature is valid. * @return Whether the ECSignature is valid.
*/ */
export function isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean { isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
assert.isHexString('data', data); assert.isHexString('data', data);
assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema); assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
assert.isETHAddressHex('signerAddress', signerAddress); assert.isETHAddressHex('signerAddress', signerAddress);
@@ -188,25 +200,25 @@ export function isValidECSignature(data: string, signature: ECSignature, signerA
} catch (err) { } catch (err) {
return false; return false;
} }
} },
/**
/**
* Signs an orderHash and returns it's elliptic curve signature. * Signs an orderHash and returns it's elliptic curve signature.
* This method currently supports TestRPC, Geth and Parity above and below V1.6.6 * This method currently supports TestRPC, Geth and Parity above and below V1.6.6
* @param provider The provider to use for JSON RPC calls
* @param orderHash Hex encoded orderHash to sign. * @param orderHash Hex encoded orderHash to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address * @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. * must be available via the Provider supplied to 0x.js.
* @param hashPrefixOpts Different signers add/require different prefixes be appended to the message being signed. * @param messagePrefixOpts Different signers add/require different prefixes be appended to the message being signed.
* Since we cannot know ahead of time which signer you are using, you must supply both a prefixType and * Since we cannot know ahead of time which signer you are using, you must supply both a prefixType and
* whether it must be added before calling `eth_sign` (some signers add it themselves) * whether it must be added before calling `eth_sign` (some signers add it themselves)
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash. * @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
*/ */
export async function ecSignOrderHashAsync( async ecSignOrderHashAsync(
provider: Provider, provider: Provider,
orderHash: string, orderHash: string,
signerAddress: string, signerAddress: string,
messagePrefixOpts: MessagePrefixOpts, messagePrefixOpts: MessagePrefixOpts,
): Promise<ECSignature> { ): Promise<ECSignature> {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isHexString('orderHash', orderHash); assert.isHexString('orderHash', orderHash);
assert.isETHAddressHex('signerAddress', signerAddress); assert.isETHAddressHex('signerAddress', signerAddress);
@@ -215,7 +227,7 @@ export async function ecSignOrderHashAsync(
const normalizedSignerAddress = signerAddress.toLowerCase(); const normalizedSignerAddress = signerAddress.toLowerCase();
let msgHashHex = orderHash; let msgHashHex = orderHash;
const prefixedMsgHashHex = addSignedMessagePrefix(orderHash, messagePrefixOpts.prefixType); const prefixedMsgHashHex = signatureUtils.addSignedMessagePrefix(orderHash, messagePrefixOpts.prefixType);
if (messagePrefixOpts.shouldAddPrefixBeforeCallingEthSign) { if (messagePrefixOpts.shouldAddPrefixBeforeCallingEthSign) {
msgHashHex = prefixedMsgHashHex; msgHashHex = prefixedMsgHashHex;
} }
@@ -229,7 +241,11 @@ export async function ecSignOrderHashAsync(
const validVParamValues = [27, 28]; const validVParamValues = [27, 28];
const ecSignatureVRS = parseSignatureHexAsVRS(signature); const ecSignatureVRS = parseSignatureHexAsVRS(signature);
if (_.includes(validVParamValues, ecSignatureVRS.v)) { if (_.includes(validVParamValues, ecSignatureVRS.v)) {
const isValidVRSSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureVRS, normalizedSignerAddress); const isValidVRSSignature = signatureUtils.isValidECSignature(
prefixedMsgHashHex,
ecSignatureVRS,
normalizedSignerAddress,
);
if (isValidVRSSignature) { if (isValidVRSSignature) {
return ecSignatureVRS; return ecSignatureVRS;
} }
@@ -237,23 +253,26 @@ export async function ecSignOrderHashAsync(
const ecSignatureRSV = parseSignatureHexAsRSV(signature); const ecSignatureRSV = parseSignatureHexAsRSV(signature);
if (_.includes(validVParamValues, ecSignatureRSV.v)) { if (_.includes(validVParamValues, ecSignatureRSV.v)) {
const isValidRSVSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureRSV, normalizedSignerAddress); const isValidRSVSignature = signatureUtils.isValidECSignature(
prefixedMsgHashHex,
ecSignatureRSV,
normalizedSignerAddress,
);
if (isValidRSVSignature) { if (isValidRSVSignature) {
return ecSignatureRSV; return ecSignatureRSV;
} }
} }
throw new Error(OrderError.InvalidSignature); throw new Error(OrderError.InvalidSignature);
} },
/**
/**
* Adds the relevant prefix to the message being signed. * Adds the relevant prefix to the message being signed.
* @param message Message to sign * @param message Message to sign
* @param messagePrefixType The type of message prefix to add. Different signers expect * @param messagePrefixType The type of message prefix to add. Different signers expect
* specific message prefixes. * specific message prefixes.
* @return Prefixed message * @return Prefixed message
*/ */
export function addSignedMessagePrefix(message: string, messagePrefixType: MessagePrefixType): string { addSignedMessagePrefix(message: string, messagePrefixType: MessagePrefixType): string {
assert.isString('message', message); assert.isString('message', message);
assert.doesBelongToStringEnum('messagePrefixType', messagePrefixType, MessagePrefixType); assert.doesBelongToStringEnum('messagePrefixType', messagePrefixType, MessagePrefixType);
switch (messagePrefixType) { switch (messagePrefixType) {
@@ -277,14 +296,13 @@ export function addSignedMessagePrefix(message: string, messagePrefixType: Messa
default: default:
throw new Error(`Unrecognized MessagePrefixType: ${messagePrefixType}`); throw new Error(`Unrecognized MessagePrefixType: ${messagePrefixType}`);
} }
} },
/**
/**
* Parse a 0x protocol hex-encoded signature string into it's ECSignature components * Parse a 0x protocol hex-encoded signature string into it's ECSignature components
* @param signature A hex encoded ecSignature 0x Protocol signature * @param signature A hex encoded ecSignature 0x Protocol signature
* @return An ECSignature object with r,s,v parameters * @return An ECSignature object with r,s,v parameters
*/ */
export function parseECSignature(signature: string): ECSignature { parseECSignature(signature: string): ECSignature {
assert.isHexString('signature', signature); assert.isHexString('signature', signature);
const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor]; const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor];
assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes); assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes);
@@ -294,7 +312,8 @@ export function parseECSignature(signature: string): ECSignature {
const ecSignature = parseSignatureHexAsVRS(vrsHex); const ecSignature = parseSignatureHexAsVRS(vrsHex);
return ecSignature; return ecSignature;
} },
};
function hashTrezorPersonalMessage(message: Buffer): Buffer { function hashTrezorPersonalMessage(message: Buffer): Buffer {
const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.byteLength)); const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.byteLength));

View File

@@ -5,8 +5,8 @@ import * as _ from 'lodash';
import 'mocha'; import 'mocha';
import * as Sinon from 'sinon'; import * as Sinon from 'sinon';
import { ecSignOrderHashAsync, generatePseudoRandomSalt, MessagePrefixType } from '../src'; import { generatePseudoRandomSalt, MessagePrefixType } from '../src';
import { isValidECSignature, isValidSignatureAsync } from '../src/signature_utils'; import { signatureUtils } from '../src/signature_utils';
import { chaiSetup } from './utils/chai_setup'; import { chaiSetup } from './utils/chai_setup';
import { provider, web3Wrapper } from './utils/web3_wrapper'; import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -22,12 +22,14 @@ describe('Signature utils', () => {
let address = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; let address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
it("should return false if the data doesn't pertain to the signature & address", async () => { it("should return false if the data doesn't pertain to the signature & address", async () => {
expect(await isValidSignatureAsync(provider, '0x0', ethSignSignature, address)).to.be.false(); expect(
await signatureUtils.isValidSignatureAsync(provider, '0x0', ethSignSignature, address),
).to.be.false();
}); });
it("should return false if the address doesn't pertain to the signature & data", async () => { it("should return false if the address doesn't pertain to the signature & data", async () => {
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42'; const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
expect( expect(
await isValidSignatureAsync(provider, dataHex, ethSignSignature, validUnrelatedAddress), await signatureUtils.isValidSignatureAsync(provider, dataHex, ethSignSignature, validUnrelatedAddress),
).to.be.false(); ).to.be.false();
}); });
it("should return false if the signature doesn't pertain to the dataHex & address", async () => { it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
@@ -35,18 +37,27 @@ describe('Signature utils', () => {
// tslint:disable-next-line:custom-no-magic-numbers // tslint:disable-next-line:custom-no-magic-numbers
signatureArray[5] = 'C'; // V = 28, instead of 27 signatureArray[5] = 'C'; // V = 28, instead of 27
const wrongSignature = signatureArray.join(''); const wrongSignature = signatureArray.join('');
expect(await isValidSignatureAsync(provider, dataHex, wrongSignature, address)).to.be.false(); expect(
await signatureUtils.isValidSignatureAsync(provider, dataHex, wrongSignature, address),
).to.be.false();
}); });
it('should throw if signatureType is invalid', () => { it('should throw if signatureType is invalid', () => {
const signatureArray = ethSignSignature.split(''); const signatureArray = ethSignSignature.split('');
signatureArray[3] = '9'; // SignatureType w/ index 9 doesn't exist signatureArray[3] = '9'; // SignatureType w/ index 9 doesn't exist
const signatureWithInvalidType = signatureArray.join(''); const signatureWithInvalidType = signatureArray.join('');
expect(isValidSignatureAsync(provider, dataHex, signatureWithInvalidType, address)).to.be.rejected(); expect(
signatureUtils.isValidSignatureAsync(provider, dataHex, signatureWithInvalidType, address),
).to.be.rejected();
}); });
it('should return true for a valid Ecrecover (EthSign) signature', async () => { it('should return true for a valid Ecrecover (EthSign) signature', async () => {
const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, ethSignSignature, address); const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync(
provider,
dataHex,
ethSignSignature,
address,
);
expect(isValidSignatureLocal).to.be.true(); expect(isValidSignatureLocal).to.be.true();
}); });
@@ -55,7 +66,12 @@ describe('Signature utils', () => {
address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb'; address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
const eip712Signature = const eip712Signature =
'0x1bdde07aac4bf12c12ddbb155919c43eba4146a2cfcf904a862950dbebe332554c6674975603eb5a4eaf8fd7f2e06350267e5b36cda9851a89f8bb49fe2fc9afe202'; '0x1bdde07aac4bf12c12ddbb155919c43eba4146a2cfcf904a862950dbebe332554c6674975603eb5a4eaf8fd7f2e06350267e5b36cda9851a89f8bb49fe2fc9afe202';
const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, eip712Signature, address); const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync(
provider,
dataHex,
eip712Signature,
address,
);
expect(isValidSignatureLocal).to.be.true(); expect(isValidSignatureLocal).to.be.true();
}); });
@@ -64,7 +80,12 @@ describe('Signature utils', () => {
address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb'; address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
const trezorSignature = const trezorSignature =
'0x1ce4760660e6495b5ae6723087bea073b3a99ce98ea81fdf00c240279c010e63d05b87bc34c4d67d4776e8d5aeb023a67484f4eaf0fd353b40893e5101e845cd9908'; '0x1ce4760660e6495b5ae6723087bea073b3a99ce98ea81fdf00c240279c010e63d05b87bc34c4d67d4776e8d5aeb023a67484f4eaf0fd353b40893e5101e845cd9908';
const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, trezorSignature, address); const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync(
provider,
dataHex,
trezorSignature,
address,
);
expect(isValidSignatureLocal).to.be.true(); expect(isValidSignatureLocal).to.be.true();
}); });
}); });
@@ -78,18 +99,18 @@ describe('Signature utils', () => {
const address = '0x0e5cb767cce09a7f3ca594df118aa519be5e2b5a'; const address = '0x0e5cb767cce09a7f3ca594df118aa519be5e2b5a';
it("should return false if the data doesn't pertain to the signature & address", async () => { it("should return false if the data doesn't pertain to the signature & address", async () => {
expect(isValidECSignature('0x0', signature, address)).to.be.false(); expect(signatureUtils.isValidECSignature('0x0', signature, address)).to.be.false();
}); });
it("should return false if the address doesn't pertain to the signature & data", async () => { it("should return false if the address doesn't pertain to the signature & data", async () => {
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42'; const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
expect(isValidECSignature(data, signature, validUnrelatedAddress)).to.be.false(); expect(signatureUtils.isValidECSignature(data, signature, validUnrelatedAddress)).to.be.false();
}); });
it("should return false if the signature doesn't pertain to the data & address", async () => { it("should return false if the signature doesn't pertain to the data & address", async () => {
const wrongSignature = _.assign({}, signature, { v: 28 }); const wrongSignature = _.assign({}, signature, { v: 28 });
expect(isValidECSignature(data, wrongSignature, address)).to.be.false(); expect(signatureUtils.isValidECSignature(data, wrongSignature, address)).to.be.false();
}); });
it('should return true if the signature does pertain to the data & address', async () => { it('should return true if the signature does pertain to the data & address', async () => {
const isValidSignatureLocal = isValidECSignature(data, signature, address); const isValidSignatureLocal = signatureUtils.isValidECSignature(data, signature, address);
expect(isValidSignatureLocal).to.be.true(); expect(isValidSignatureLocal).to.be.true();
}); });
}); });
@@ -129,7 +150,12 @@ describe('Signature utils', () => {
prefixType: MessagePrefixType.EthSign, prefixType: MessagePrefixType.EthSign,
shouldAddPrefixBeforeCallingEthSign: false, shouldAddPrefixBeforeCallingEthSign: false,
}; };
const ecSignature = await ecSignOrderHashAsync(provider, orderHash, makerAddress, messagePrefixOpts); const ecSignature = await signatureUtils.ecSignOrderHashAsync(
provider,
orderHash,
makerAddress,
messagePrefixOpts,
);
expect(ecSignature).to.deep.equal(expectedECSignature); expect(ecSignature).to.deep.equal(expectedECSignature);
}); });
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => { it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
@@ -162,7 +188,12 @@ describe('Signature utils', () => {
prefixType: MessagePrefixType.EthSign, prefixType: MessagePrefixType.EthSign,
shouldAddPrefixBeforeCallingEthSign: false, shouldAddPrefixBeforeCallingEthSign: false,
}; };
const ecSignature = await ecSignOrderHashAsync(fakeProvider, orderHash, makerAddress, messagePrefixOpts); const ecSignature = await signatureUtils.ecSignOrderHashAsync(
fakeProvider,
orderHash,
makerAddress,
messagePrefixOpts,
);
expect(ecSignature).to.deep.equal(expectedECSignature); expect(ecSignature).to.deep.equal(expectedECSignature);
}); });
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => { it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
@@ -192,7 +223,12 @@ describe('Signature utils', () => {
prefixType: MessagePrefixType.EthSign, prefixType: MessagePrefixType.EthSign,
shouldAddPrefixBeforeCallingEthSign: false, shouldAddPrefixBeforeCallingEthSign: false,
}; };
const ecSignature = await ecSignOrderHashAsync(fakeProvider, orderHash, makerAddress, messagePrefixOpts); const ecSignature = await signatureUtils.ecSignOrderHashAsync(
fakeProvider,
orderHash,
makerAddress,
messagePrefixOpts,
);
expect(ecSignature).to.deep.equal(expectedECSignature); expect(ecSignature).to.deep.equal(expectedECSignature);
}); });
}); });

View File

@@ -7,7 +7,7 @@ import { BigNumber } from '@0xproject/utils';
// tslint:enable:no-unused-variable // tslint:enable:no-unused-variable
import { Provider } from 'ethereum-types'; import { Provider } from 'ethereum-types';
import { isValidSignatureAsync } from '@0xproject/order-utils'; import { signatureUtils } from '@0xproject/order-utils';
export const assert = { export const assert = {
...sharedAssert, ...sharedAssert,
@@ -17,7 +17,7 @@ export const assert = {
signature: string, signature: string,
signerAddress: string, signerAddress: string,
): Promise<void> { ): Promise<void> {
const isValid = await isValidSignatureAsync(provider, orderHash, signature, signerAddress); const isValid = await signatureUtils.isValidSignatureAsync(provider, orderHash, signature, signerAddress);
assert.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`); assert.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
}, },
}; };