aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-06-02 02:34:12 +0800
committerFabio Berger <me@fabioberger.com>2018-06-02 02:34:12 +0800
commit8cd4578d839c4311ff69ce9bb0245867e25dcf6d (patch)
treea2588e41113fa5eb41f7528ad237368bb62d967e
parent152082e1820f89bf65e99b5b3ecfe9d3946e3148 (diff)
downloaddexon-sol-tools-8cd4578d839c4311ff69ce9bb0245867e25dcf6d.tar.gz
dexon-sol-tools-8cd4578d839c4311ff69ce9bb0245867e25dcf6d.tar.zst
dexon-sol-tools-8cd4578d839c4311ff69ce9bb0245867e25dcf6d.zip
Add signature specific validation methods, and other refactors
-rw-r--r--packages/order-utils/src/assert.ts14
-rw-r--r--packages/order-utils/src/signature_utils.ts120
-rw-r--r--packages/order-utils/src/utils.ts9
-rw-r--r--packages/order-utils/test/signature_utils_test.ts2
-rw-r--r--packages/types/src/index.ts8
5 files changed, 98 insertions, 55 deletions
diff --git a/packages/order-utils/src/assert.ts b/packages/order-utils/src/assert.ts
index 07cde453a..a1318b9b8 100644
--- a/packages/order-utils/src/assert.ts
+++ b/packages/order-utils/src/assert.ts
@@ -3,11 +3,13 @@ import { assert as sharedAssert } from '@0xproject/assert';
// tslint:disable-next-line:no-unused-variable
import { Schema } from '@0xproject/json-schemas';
// tslint:disable-next-line:no-unused-variable
-import { ECSignature } from '@0xproject/types';
+import { ECSignature, SignatureType } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
+import { utils } from './utils';
+
export const assert = {
...sharedAssert,
async isSenderAddressAsync(
@@ -22,4 +24,14 @@ export const assert = {
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
);
},
+ isOneOfExpectedSignatureTypes(signature: string, signatureTypes: SignatureType[]): void {
+ sharedAssert.isHexString('signature', signature);
+ const signatureTypeIndexIfExists = utils.getSignatureTypeIndexIfExists(signature);
+ const isExpectedSignatureType = _.includes(signatureTypes, signatureTypeIndexIfExists);
+ if (!isExpectedSignatureType) {
+ throw new Error(
+ `Unexpected signatureType: ${signatureTypeIndexIfExists}. Valid signature types: ${signatureTypes}`,
+ );
+ }
+ },
};
diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts
index 427448260..dadf5052c 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, Provider, SignatureType } from '@0xproject/types';
+import { ECSignature, Provider, SignatureType, ValidatorSignature } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
@@ -7,9 +7,10 @@ import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { assert } from './assert';
import { ExchangeContract } from './generated_contract_wrappers/exchange';
-import { IWalletContract } from './generated_contract_wrappers/i_signer';
import { IValidatorContract } from './generated_contract_wrappers/i_validator';
+import { IWalletContract } from './generated_contract_wrappers/i_wallet';
import { MessagePrefixOpts, MessagePrefixType, OrderError } from './types';
+import { utils } from './utils';
/**
* Verifies that the provided signature is valid according to the 0x Protocol smart contracts
@@ -25,7 +26,7 @@ export async function isValidSignatureAsync(
signature: string,
signerAddress: string,
): Promise<boolean> {
- const signatureTypeIndexIfExists = getSignatureTypeIndexIfExists(signature);
+ const signatureTypeIndexIfExists = utils.getSignatureTypeIndexIfExists(signature);
if (_.isUndefined(signatureTypeIndexIfExists)) {
throw new Error(`Unrecognized signatureType in signature: ${signature}`);
}
@@ -52,30 +53,17 @@ export async function isValidSignatureAsync(
throw new Error('Caller signature type cannot be validated off-chain');
case SignatureType.Wallet: {
- const signerContract = new IWalletContract(artifacts.IWallet.abi, signerAddress, provider);
- const isValid = await signerContract.isValidSignature.callAsync(data, signature);
+ const isValid = await isValidWalletSignatureAsync(provider, data, signature, signerAddress);
return isValid;
}
case SignatureType.Validator: {
- const validatorAddress = getValidatorAddressFromSignature(signature);
- const exchangeContract = new ExchangeContract(artifacts.Exchange.abi, signerAddress, provider);
- const isValidatorApproved = await exchangeContract.allowedValidators.callAsync(
- signerAddress,
- validatorAddress,
- );
- if (!isValidatorApproved) {
- throw new Error(`Validator ${validatorAddress} was not pre-approved by ${signerAddress}.`);
- }
-
- const validatorSignature = getValidatorSignatureFromSignature(signature);
- const validatorContract = new IValidatorContract(artifacts.IValidator.abi, signerAddress, provider);
- const isValid = await validatorContract.isValidSignature.callAsync(data, signerAddress, validatorSignature);
+ const isValid = await isValidValidatorSignatureAsync(provider, data, signature, signerAddress);
return isValid;
}
case SignatureType.PreSigned: {
- return isValidPresignedSignatureAsync(provider, data, signature, signerAddress);
+ return isValidPresignedSignatureAsync(provider, data, signerAddress);
}
case SignatureType.Trezor: {
@@ -99,7 +87,6 @@ export async function isValidSignatureAsync(
export async function isValidPresignedSignatureAsync(
provider: Provider,
data: string,
- signature: string,
signerAddress: string,
): Promise<boolean> {
const exchangeContract = new ExchangeContract(artifacts.Exchange.abi, signerAddress, provider);
@@ -108,6 +95,58 @@ export async function isValidPresignedSignatureAsync(
}
/**
+ * 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> {
+ // tslint:disable-next-line:custom-no-magic-numbers
+ const signatureWithoutType = signature.slice(-2);
+ const walletContract = new IWalletContract(artifacts.IWallet.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> {
+ const validatorSignature = parseValidatorSignature(signature);
+ const exchangeContract = new ExchangeContract(artifacts.Exchange.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}.`);
+ }
+
+ const validatorContract = new IValidatorContract(artifacts.IValidator.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.
@@ -220,13 +259,8 @@ function hashTrezorPersonalMessage(message: Buffer): Buffer {
}
function parseECSignature(signature: string): ECSignature {
- assert.isHexString('signature', signature);
- const signatureTypeIndexIfExists = getSignatureTypeIndexIfExists(signature);
const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor];
- const isECSignatureType = _.includes(ecSignatureTypes, signatureTypeIndexIfExists);
- if (!isECSignatureType) {
- throw new Error(`Cannot parse non-ECSignature type: ${signatureTypeIndexIfExists}`);
- }
+ assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes);
// tslint:disable-next-line:custom-no-magic-numbers
const vrsHex = signature.slice(0, -2);
@@ -235,35 +269,17 @@ function parseECSignature(signature: string): ECSignature {
return ecSignature;
}
-function getValidatorSignatureFromSignature(signature: string): string {
- const signatureTypeIndex = getSignatureTypeIndexIfExists(signature);
- if (signatureTypeIndex !== SignatureType.Validator) {
- throw new Error('Cannot get validator address from non-validator signature');
- }
- // tslint:disable-next-line:custom-no-magic-numbers
- const validatorSignature = signature.slice(0, -22);
+function parseValidatorSignature(signature: string): ValidatorSignature {
+ assert.isOneOfExpectedSignatureTypes(signature, [SignatureType.Validator]);
+ // tslint:disable:custom-no-magic-numbers
+ const validatorSignature = {
+ validatorAddress: signature.slice(-22, -2),
+ signature: signature.slice(0, -22),
+ };
+ // tslint:enable:custom-no-magic-numbers
return validatorSignature;
}
-function getValidatorAddressFromSignature(signature: string): string {
- const signatureTypeIndex = getSignatureTypeIndexIfExists(signature);
- if (signatureTypeIndex !== SignatureType.Validator) {
- throw new Error('Cannot get validator address from non-validator signature');
- }
- // tslint:disable-next-line:custom-no-magic-numbers
- const validatorAddress = signature.slice(-22, -2);
- return `0x${validatorAddress}`;
-}
-
-function getSignatureTypeIndexIfExists(signature: string): number {
- const unprefixedSignature = ethUtil.stripHexPrefix(signature);
- // tslint:disable-next-line:custom-no-magic-numbers
- const signatureTypeHex = unprefixedSignature.slice(-2);
- const base = 16;
- const signatureTypeInt = parseInt(signatureTypeHex, base);
- return signatureTypeInt;
-}
-
function parseSignatureHexAsVRS(signatureHex: string): ECSignature {
const signatureBuffer = ethUtil.toBuffer(signatureHex);
let v = signatureBuffer[0];
diff --git a/packages/order-utils/src/utils.ts b/packages/order-utils/src/utils.ts
new file mode 100644
index 000000000..3b465cece
--- /dev/null
+++ b/packages/order-utils/src/utils.ts
@@ -0,0 +1,9 @@
+export const utils = {
+ getSignatureTypeIndexIfExists(signature: string): number {
+ // tslint:disable-next-line:custom-no-magic-numbers
+ const signatureTypeHex = signature.slice(-2);
+ const base = 16;
+ const signatureTypeInt = parseInt(signatureTypeHex, base);
+ return signatureTypeInt;
+ },
+};
diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts
index 4ecd14877..16d961ed7 100644
--- a/packages/order-utils/test/signature_utils_test.ts
+++ b/packages/order-utils/test/signature_utils_test.ts
@@ -69,8 +69,6 @@ describe('Signature utils', () => {
const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, trezorSignature, address);
expect(isValidSignatureLocal).to.be.true();
});
-
- // TODO: Add remaining signature tests: Validator, Wallet, Presigned?
});
describe('#isValidECSignature', () => {
const signature = {
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index bb8fe896d..b1d6f97cb 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -326,6 +326,14 @@ export interface ECSignature {
}
/**
+ * Validator signature components
+ */
+export interface ValidatorSignature {
+ validatorAddress: string;
+ signature: string;
+}
+
+/**
* Errors originating from the 0x exchange contract
*/
export enum ExchangeContractErrs {