@0x/contracts-zero-ex: add SignatureValidator and MetaTransactions features.
This commit is contained in:
232
contracts/zero-ex/test/features/signature_validator_test.ts
Normal file
232
contracts/zero-ex/test/features/signature_validator_test.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import { blockchainTests, constants, expect, randomAddress, signingUtils } from '@0x/contracts-test-utils';
|
||||
import { signatureUtils } from '@0x/order-utils';
|
||||
import { SignatureType } from '@0x/types';
|
||||
import { hexUtils, ZeroExRevertErrors } from '@0x/utils';
|
||||
import * as ethjs from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { SignatureValidatorContract, ZeroExContract } from '../../src/wrappers';
|
||||
import { abis } from '../utils/abis';
|
||||
import { fullMigrateAsync } from '../utils/migration';
|
||||
|
||||
const { NULL_BYTES } = constants;
|
||||
|
||||
blockchainTests.resets('SignatureValidator feature', env => {
|
||||
let owner: string;
|
||||
let signers: string[];
|
||||
let zeroEx: ZeroExContract;
|
||||
let feature: SignatureValidatorContract;
|
||||
|
||||
before(async () => {
|
||||
[owner, ...signers] = await env.getAccountAddressesAsync();
|
||||
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults);
|
||||
feature = new SignatureValidatorContract(zeroEx.address, env.provider, env.txDefaults, abis);
|
||||
});
|
||||
|
||||
describe('validateHashSignature()', () => {
|
||||
it('can validate an eth_sign signature', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = await signatureUtils.ecSignHashAsync(env.provider, hash, signer);
|
||||
await feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
});
|
||||
|
||||
it('rejects a wrong eth_sign signature', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = await signatureUtils.ecSignHashAsync(env.provider, hash, signer);
|
||||
const notSigner = randomAddress();
|
||||
const tx = feature.validateHashSignature(hash, notSigner, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.WrongSigner,
|
||||
hash,
|
||||
notSigner,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an eth_sign if ecrecover() fails', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = hexUtils.concat(hexUtils.random(65), SignatureType.EthSign);
|
||||
const tx = feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.WrongSigner,
|
||||
hash,
|
||||
signer,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a too short eth_sign signature', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = hexUtils.slice(await signatureUtils.ecSignHashAsync(env.provider, hash, signer), 1);
|
||||
const notSigner = randomAddress();
|
||||
const tx = feature.validateHashSignature(hash, notSigner, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.InvalidLength,
|
||||
hash,
|
||||
notSigner,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('can validate an eip712 signature', async () => {
|
||||
const privateKey = hexUtils.random();
|
||||
const signer = hexUtils.toHex(ethjs.privateToAddress(ethjs.toBuffer(privateKey)));
|
||||
const hash = hexUtils.random();
|
||||
const signature = hexUtils.toHex(
|
||||
signingUtils.signMessage(ethjs.toBuffer(hash), ethjs.toBuffer(privateKey), SignatureType.EIP712),
|
||||
);
|
||||
await feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
});
|
||||
|
||||
it('rejects a wrong eip712 signature', async () => {
|
||||
const privateKey = hexUtils.random();
|
||||
const hash = hexUtils.random();
|
||||
const signature = hexUtils.toHex(
|
||||
signingUtils.signMessage(ethjs.toBuffer(hash), ethjs.toBuffer(privateKey), SignatureType.EIP712),
|
||||
);
|
||||
const notSigner = randomAddress();
|
||||
const tx = feature.validateHashSignature(hash, notSigner, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.WrongSigner,
|
||||
hash,
|
||||
notSigner,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an eip712 if ecrecover() fails', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = hexUtils.concat(hexUtils.random(65), SignatureType.EIP712);
|
||||
const tx = feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.WrongSigner,
|
||||
hash,
|
||||
signer,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a too short eip712 signature', async () => {
|
||||
const privateKey = hexUtils.random();
|
||||
const signer = hexUtils.toHex(ethjs.privateToAddress(ethjs.toBuffer(privateKey)));
|
||||
const hash = hexUtils.random();
|
||||
const signature = hexUtils.slice(
|
||||
hexUtils.toHex(
|
||||
signingUtils.signMessage(ethjs.toBuffer(hash), ethjs.toBuffer(privateKey), SignatureType.EIP712),
|
||||
),
|
||||
1,
|
||||
);
|
||||
const tx = feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.InvalidLength,
|
||||
hash,
|
||||
signer,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an INVALID signature type', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = hexUtils.concat(
|
||||
hexUtils.slice(await signatureUtils.ecSignHashAsync(env.provider, hash, signer), 0, -1),
|
||||
SignatureType.Invalid,
|
||||
);
|
||||
const tx = feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.AlwaysInvalid,
|
||||
hash,
|
||||
signer,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an ILLEGAL signature type', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = hexUtils.concat(
|
||||
hexUtils.slice(await signatureUtils.ecSignHashAsync(env.provider, hash, signer), 0, -1),
|
||||
SignatureType.Illegal,
|
||||
);
|
||||
const tx = feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.Illegal,
|
||||
hash,
|
||||
signer,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an unsupported signature type', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = hexUtils.concat(
|
||||
hexUtils.slice(await signatureUtils.ecSignHashAsync(env.provider, hash, signer), 0, -1),
|
||||
SignatureType.Wallet,
|
||||
);
|
||||
const tx = feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.Unsupported,
|
||||
hash,
|
||||
signer,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an empty signature type', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = NULL_BYTES;
|
||||
const tx = feature.validateHashSignature(hash, signer, signature).callAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.SignatureValidator.SignatureValidationError(
|
||||
ZeroExRevertErrors.SignatureValidator.SignatureValidationErrorCodes.InvalidLength,
|
||||
hash,
|
||||
signer,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValidHashSignature()', () => {
|
||||
it('returns true on valid signature', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = await signatureUtils.ecSignHashAsync(env.provider, hash, signer);
|
||||
const r = await feature.isValidHashSignature(hash, signer, signature).callAsync();
|
||||
expect(r).to.eq(true);
|
||||
});
|
||||
|
||||
it('returns false on invalid signature', async () => {
|
||||
const hash = hexUtils.random();
|
||||
const signer = _.sampleSize(signers, 1)[0];
|
||||
const signature = await signatureUtils.ecSignHashAsync(env.provider, hash, signer);
|
||||
const r = await feature.isValidHashSignature(hash, randomAddress(), signature).callAsync();
|
||||
expect(r).to.eq(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user