diff options
author | Greg Hysen <greg.hysen@gmail.com> | 2018-06-20 08:20:53 +0800 |
---|---|---|
committer | Greg Hysen <greg.hysen@gmail.com> | 2018-06-21 04:54:39 +0800 |
commit | d46e3f677805c8e3e4b4873fb9b0cec2988a4d63 (patch) | |
tree | e23a9011a51b4494bfdee17697cfde66768ce924 /packages/contracts/test/exchange/signature_validator.ts | |
parent | 6fe31587780ab309015d392747cebe61ff82b679 (diff) | |
download | dexon-0x-contracts-d46e3f677805c8e3e4b4873fb9b0cec2988a4d63.tar.gz dexon-0x-contracts-d46e3f677805c8e3e4b4873fb9b0cec2988a4d63.tar.zst dexon-0x-contracts-d46e3f677805c8e3e4b4873fb9b0cec2988a4d63.zip |
Twenty new tests for MixinSignatureValidator. Fixed handling of unsupported types. Fixed trezor prefix.
Diffstat (limited to 'packages/contracts/test/exchange/signature_validator.ts')
-rw-r--r-- | packages/contracts/test/exchange/signature_validator.ts | 401 |
1 files changed, 386 insertions, 15 deletions
diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index c39fd6ee4..8f796361f 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -1,12 +1,16 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; -import { assetProxyUtils, orderHashUtils } from '@0xproject/order-utils'; -import { SignedOrder } from '@0xproject/types'; +import { addSignedMessagePrefix, assetProxyUtils, MessagePrefixType, orderHashUtils } from '@0xproject/order-utils'; +import { SignatureType, SignedOrder } from '@0xproject/types'; import * as chai from 'chai'; import ethUtil = require('ethereumjs-util'); +import * as _ from 'lodash'; import { TestSignatureValidatorContract } from '../../src/generated_contract_wrappers/test_signature_validator'; +import { TestValidatorContract } from '../../src/generated_contract_wrappers/test_validator'; +import { TestWalletContract } from '../../src/generated_contract_wrappers/test_wallet'; import { addressUtils } from '../../src/utils/address_utils'; import { artifacts } from '../../src/utils/artifacts'; +import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions'; import { chaiSetup } from '../../src/utils/chai_setup'; import { constants } from '../../src/utils/constants'; import { OrderFactory } from '../../src/utils/order_factory'; @@ -21,6 +25,12 @@ describe('MixinSignatureValidator', () => { let signedOrder: SignedOrder; let orderFactory: OrderFactory; let signatureValidator: TestSignatureValidatorContract; + let testWallet: TestWalletContract; + let testValidator: TestValidatorContract; + let signerAddress: string; + let signerPrivateKey: Buffer; + let notSignerAddress: string; + let notSignerPrivateKey: Buffer; before(async () => { await blockchainLifecycle.startAsync(); @@ -31,11 +41,31 @@ describe('MixinSignatureValidator', () => { before(async () => { const accounts = await web3Wrapper.getAvailableAddressesAsync(); const makerAddress = accounts[0]; + signerAddress = makerAddress; + notSignerAddress = accounts[1]; signatureValidator = await TestSignatureValidatorContract.deployFrom0xArtifactAsync( artifacts.TestSignatureValidator, provider, txDefaults, ); + testWallet = await TestWalletContract.deployFrom0xArtifactAsync( + artifacts.TestWallet, + provider, + txDefaults, + signerAddress, + ); + testValidator = await TestValidatorContract.deployFrom0xArtifactAsync( + artifacts.TestValidator, + provider, + txDefaults, + signerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(testValidator.address, true, { + from: signerAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); const defaultOrderParams = { ...constants.STATIC_ORDER_PARAMS, @@ -45,8 +75,9 @@ describe('MixinSignatureValidator', () => { makerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), takerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); + signerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; + notSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(notSignerAddress)]; + orderFactory = new OrderFactory(signerPrivateKey, defaultOrderParams); }); beforeEach(async () => { @@ -61,29 +92,369 @@ describe('MixinSignatureValidator', () => { signedOrder = orderFactory.newSignedOrder(); }); - it('should return true with a valid signature', async () => { + it('should revert with an empty signature', async () => { + const emptySignature = '0x'; + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + return expectRevertOrAlwaysFailingTransactionAsync( + signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signedOrder.makerAddress, + emptySignature, + ), + ); + }); + + it('should revert with an unsupported signature type', async () => { + const unsupportedSignatureType = SignatureType.NSignatureTypes; + const unsupportedSignatureHex = `0x${unsupportedSignatureType}`; + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + return expectRevertOrAlwaysFailingTransactionAsync( + signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signedOrder.makerAddress, + unsupportedSignatureHex, + ), + ); + }); + + it('should revert when SignatureType=Illegal', async () => { + const unsupportedSignatureHex = `0x${SignatureType.Illegal}`; + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + return expectRevertOrAlwaysFailingTransactionAsync( + signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signedOrder.makerAddress, + unsupportedSignatureHex, + ), + ); + }); + + it('should return false when SignatureType=Invalid and signature has a length of zero', async () => { + const signatureHex = `0x${SignatureType.Invalid}`; + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signedOrder.makerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.false(); + }); + + it('should revert when SignatureType=Invalid and signature length is non-zero', async () => { + const fillerData = ethUtil.toBuffer('0xdeadbeef'); + const signatureType = ethUtil.toBuffer(`0x${SignatureType.Invalid}`); + const signatureBuffer = Buffer.concat([fillerData, signatureType]); + const signatureHex = ethUtil.bufferToHex(signatureBuffer); + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + return expectRevertOrAlwaysFailingTransactionAsync( + signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signedOrder.makerAddress, + signatureHex, + ), + ); + }); + + it('should return true when SignatureType=EIP712 and signature is valid', async () => { + // Create EIP712 signature const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashBuffer = ethUtil.toBuffer(orderHashHex); + const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey); + // Create 0x signature from EIP712 signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.EIP712}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.true(); + }); + + it('should return true when SignatureType=EIP712 and signature is valid', async () => { + // Create EIP712 signature + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashBuffer = ethUtil.toBuffer(orderHashHex); + const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey); + // Create 0x signature from EIP712 signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.EIP712}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + notSignerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.false(); + }); + + it('should return true when SignatureType=EthSign and signature is valid', async () => { + // Create EthSign signature + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.EthSign); + const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex); + const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey); + // Create 0x signature from EthSign signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.EthSign}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.true(); + }); + + it('should return true when SignatureType=EthSign and signature is invalid', async () => { + // Create EthSign signature + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashWithEthSignPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.EthSign); + const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex); + const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey); + // Create 0x signature from EthSign signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.EthSign}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature. + // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress` + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + notSignerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.false(); + }); + + it('should return true when SignatureType=Caller and signer is caller', async () => { + const signature = ethUtil.toBuffer(`0x${SignatureType.Caller}`); + const signatureHex = ethUtil.bufferToHex(signature); + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signerAddress, + signatureHex, + { from: signerAddress }, + ); + expect(isValidSignature).to.be.true(); + }); + + it('should return false when SignatureType=Caller and signer is not caller', async () => { + const signature = ethUtil.toBuffer(`0x${SignatureType.Caller}`); + const signatureHex = ethUtil.bufferToHex(signature); + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signerAddress, + signatureHex, + { from: notSignerAddress }, + ); + expect(isValidSignature).to.be.false(); + }); + + it('should return true when SignatureType=Wallet and signature is valid', async () => { + // Create EIP712 signature + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashBuffer = ethUtil.toBuffer(orderHashHex); + const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey); + // Create 0x signature from EIP712 signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.Wallet}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + testWallet.address, + signatureHex, + ); + expect(isValidSignature).to.be.true(); + }); + + it('should return false when SignatureType=Wallet and signature is invalid', async () => { + // Create EIP712 signature using a private key that does not belong to the wallet owner. + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashBuffer = ethUtil.toBuffer(orderHashHex); + const notWalletOwnerPrivateKey = notSignerPrivateKey; + const ecSignature = ethUtil.ecsign(orderHashBuffer, notWalletOwnerPrivateKey); + // Create 0x signature from EIP712 signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.Wallet}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + testWallet.address, + signatureHex, + ); + expect(isValidSignature).to.be.false(); + }); + + it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => { + const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`); + const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`); + const signature = Buffer.concat([validatorAddress, signatureType]); + const signatureHex = ethUtil.bufferToHex(signature); + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.true(); + }); + + it('should return false when SignatureType=Validator, signature is invalid and validator is approved', async () => { + const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`); + const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`); + const signature = Buffer.concat([validatorAddress, signatureType]); + const signatureHex = ethUtil.bufferToHex(signature); + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + notSignerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.false(); + }); + + it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => { + // Set approval of signature validator to false + await web3Wrapper.awaitTransactionSuccessAsync( + await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync( + testValidator.address, + false, + { from: signerAddress }, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Validate signature + const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`); + const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`); + const signature = Buffer.concat([validatorAddress, signatureType]); + const signatureHex = ethUtil.bufferToHex(signature); + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.false(); + // Set approval of signature validator back to true + await web3Wrapper.awaitTransactionSuccessAsync( + await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync( + testValidator.address, + true, + { from: signerAddress }, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + }); + + it('should return true when SignatureType=Trezor and signature is valid', async () => { + // Create Trezor signature + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.Trezor); + const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex); + const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey); + // Create 0x signature from Trezor signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.Trezor}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + signerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.true(); + }); + + it('should return true when SignatureType=Trezor and signature is invalid', async () => { + // Create Trezor signature + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashWithTrezorPrefixHex = addSignedMessagePrefix(orderHashHex, MessagePrefixType.Trezor); + const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex); + const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey); + // Create 0x signature from Trezor signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.Trezor}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature. + // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress` + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + notSignerAddress, + signatureHex, + ); + expect(isValidSignature).to.be.false(); + }); + + it('should return true when SignatureType=Presigned and signer has presigned hash', async () => { + // Presign hash + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + await web3Wrapper.awaitTransactionSuccessAsync( + await signatureValidator.preSign.sendTransactionAsync( + orderHashHex, + signedOrder.makerAddress, + signedOrder.signature, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Validate presigned signature + const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`); + const signatureHex = ethUtil.bufferToHex(signature); const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( orderHashHex, signedOrder.makerAddress, - signedOrder.signature, + signatureHex, ); expect(isValidSignature).to.be.true(); }); - it('should return false with an invalid signature', async () => { - const v = ethUtil.toBuffer(signedOrder.signature.slice(0, 4)); - const invalidR = ethUtil.sha3('invalidR'); - const invalidS = ethUtil.sha3('invalidS'); - const signatureType = ethUtil.toBuffer(`0x${signedOrder.signature.slice(-2)}`); - const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]); - const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`; - signedOrder.signature = invalidSigHex; + it('should return false when SignatureType=Presigned has not presigned hash', async () => { + const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`); + const signatureHex = ethUtil.bufferToHex(signature); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( orderHashHex, signedOrder.makerAddress, - signedOrder.signature, + signatureHex, ); expect(isValidSignature).to.be.false(); }); |