Fixes #1998, still needs Integration testing

This commit is contained in:
Jan-Gerrit Harms
2019-07-29 21:39:21 +02:00
parent aa29526ae4
commit 72b8ef33d9
3 changed files with 78 additions and 20 deletions

View File

@@ -20,7 +20,7 @@ import { assert } from './assert';
import { eip712Utils } from './eip712_utils';
import { orderHashUtils } from './order_hash';
import { transactionHashUtils } from './transaction_hash';
import { TypedDataError } from './types';
import { PresignedSignatureOpts, SignatureValidationOpts, TypedDataError, ValidatorSignatureOpts } from './types';
import { utils } from './utils';
export const signatureUtils = {
@@ -38,6 +38,7 @@ export const signatureUtils = {
data: string,
signature: string,
signerAddress: string,
signatureValidationOpts?: SignatureValidationOpts,
): Promise<boolean> {
const provider = providerUtils.standardizeOrThrow(supportedProvider);
assert.isHexString('data', data);
@@ -75,17 +76,22 @@ export const signatureUtils = {
}
case SignatureType.Validator: {
const exchangeAddress = signatureValidationOpts &&
(signatureValidationOpts as ValidatorSignatureOpts).exchangeAddress;
const isValid = await signatureUtils.isValidValidatorSignatureAsync(
provider,
data,
signature,
signerAddress,
exchangeAddress,
);
return isValid;
}
case SignatureType.PreSigned: {
return signatureUtils.isValidPresignedSignatureAsync(provider, data, signerAddress);
const exchangeAddress = signatureValidationOpts &&
(signatureValidationOpts as PresignedSignatureOpts).exchangeAddress;
return signatureUtils.isValidPresignedSignatureAsync(provider, data, signerAddress, exchangeAddress);
}
default:
@@ -103,14 +109,23 @@ export const signatureUtils = {
supportedProvider: SupportedProvider,
data: string,
signerAddress: string,
exchangeAddress?: string,
): Promise<boolean> {
const provider = providerUtils.standardizeOrThrow(supportedProvider);
assert.isHexString('data', data);
assert.isETHAddressHex('signerAddress', signerAddress);
const web3Wrapper = new Web3Wrapper(provider);
const networkId = await web3Wrapper.getNetworkIdAsync();
const addresses = getContractAddressesForNetworkOrThrow(networkId);
const exchangeContract = new ExchangeContract(addresses.exchange, provider);
let exchangeContract: ExchangeContract;
if (exchangeAddress) {
assert.isETHAddressHex('exchange', exchangeAddress);
exchangeContract = new ExchangeContract(exchangeAddress, provider);
} else {
const web3Wrapper = new Web3Wrapper(provider);
const networkId = await web3Wrapper.getNetworkIdAsync();
const addresses = getContractAddressesForNetworkOrThrow(networkId);
exchangeContract = new ExchangeContract(addresses.exchange, provider);
}
const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress);
return isValid;
},
@@ -151,13 +166,25 @@ export const signatureUtils = {
data: string,
signature: string,
signerAddress: string,
exchangeAddress?: string,
): Promise<boolean> {
const provider = providerUtils.standardizeOrThrow(supportedProvider);
assert.isHexString('data', data);
assert.isHexString('signature', signature);
assert.isETHAddressHex('signerAddress', signerAddress);
const validatorSignature = parseValidatorSignature(signature);
const exchangeContract = new ExchangeContract(signerAddress, provider);
let exchangeContract: ExchangeContract;
if (exchangeAddress) {
assert.isETHAddressHex('exchange', exchangeAddress);
exchangeContract = new ExchangeContract(exchangeAddress, provider);
} else {
const web3Wrapper = new Web3Wrapper(provider);
const networkId = await web3Wrapper.getNetworkIdAsync();
const addresses = getContractAddressesForNetworkOrThrow(networkId);
exchangeContract = new ExchangeContract(addresses.exchange, provider);
}
const validatorSignature = signatureUtils.parseValidatorSignature(signature);
const isValidatorApproved = await exchangeContract.allowedValidators.callAsync(
signerAddress,
validatorSignature.validatorAddress,
@@ -168,7 +195,7 @@ export const signatureUtils = {
);
}
const validatorContract = new IValidatorContract(signerAddress, provider);
const validatorContract = new IValidatorContract(validatorSignature.signature, provider);
const isValid = await validatorContract.isValidSignature.callAsync(
data,
signerAddress,
@@ -485,18 +512,23 @@ export const signatureUtils = {
return ecSignature;
},
};
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;
}
/**
* Parse a hex-encoded Validator signature into validator address and signature components
* @param signature A hex encoded Validator 0x Protocol signature
* @return A ValidatorSignature with validatorAddress and signature parameters
*/
parseValidatorSignature(signature: string): ValidatorSignature {
assert.isOneOfExpectedSignatureTypes(signature, [SignatureType.Validator]);
// tslint:disable:custom-no-magic-numbers
const validatorSignature = {
validatorAddress: `0x${signature.slice(-42, -2)}`,
signature: signature.slice(0, -42),
};
// tslint:enable:custom-no-magic-numbers
return validatorSignature;
},
};
function parseSignatureHexAsVRS(signatureHex: string): ECSignature {
const signatureBuffer = ethUtil.toBuffer(signatureHex);

View File

@@ -25,6 +25,15 @@ export interface CreateOrderOpts {
expirationTimeSeconds?: BigNumber;
}
export type SignatureValidationOpts = ValidatorSignatureOpts | PresignedSignatureOpts;
export interface ValidatorSignatureOpts {
exchangeAddress: string;
}
export interface PresignedSignatureOpts {
exchangeAddress: string;
}
/**
* remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter.
* You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values.

View File

@@ -157,6 +157,23 @@ describe('Signature utils', () => {
expect(salt.isLessThan(twoPow256)).to.be.true();
});
});
describe('#parseValidatorSignature', () => {
const ethSignSignature =
'0x1c3582f06356a1314dbf1c0e534c4d8e92e59b056ee607a7ff5a825f5f2cc5e6151c5cc7fdd420f5608e4d5bef108e42ad90c7a4b408caef32e24374cf387b0d7603';
const validatorAddress = '0x63ac26ad9477d6be19a5fabe394bcc4886057c53';
const signature = `${ethSignSignature}${validatorAddress.substr(2)}05`;
it('throws if signature type is not Validator type signature', () => {
expect(signatureUtils.parseValidatorSignature.bind(null, ethSignSignature)).to.throw(
'Unexpected signatureType: 3. Valid signature types: 5',
);
});
it('extracts signature and validator address', () => {
const validatorSignature = signatureUtils.parseValidatorSignature(signature);
expect(validatorSignature.validatorAddress).to.equal(validatorAddress);
expect(validatorSignature.signature).to.equal(ethSignSignature);
});
});
describe('#ecSignOrderAsync', () => {
it('should default to eth_sign if eth_signTypedData is unavailable', async () => {
const expectedSignature =