Setup blockchain snapshotting before/after every test, implemented unit tests for exchangeWrapper.isValidSignature
This commit is contained in:
parent
f4bf9fc423
commit
555bac19cb
@ -36,6 +36,7 @@
|
||||
"devDependencies": {
|
||||
"@types/bignumber.js": "^4.0.2",
|
||||
"@types/chai": "^3.5.2",
|
||||
"@types/chai-as-promised": "0.0.30",
|
||||
"@types/jsonschema": "^1.1.1",
|
||||
"@types/lodash": "^4.14.64",
|
||||
"@types/mocha": "^2.2.41",
|
||||
@ -43,6 +44,7 @@
|
||||
"awesome-typescript-loader": "^3.1.3",
|
||||
"bignumber.js": "^4.0.2",
|
||||
"chai": "^3.5.0",
|
||||
"chai-as-promised": "^6.0.0",
|
||||
"chai-bignumber": "^2.0.0",
|
||||
"copyfiles": "^1.2.0",
|
||||
"json-loader": "^0.5.4",
|
||||
@ -50,12 +52,15 @@
|
||||
"npm-run-all": "^4.0.2",
|
||||
"nyc": "^10.3.2",
|
||||
"opn-cli": "^3.1.0",
|
||||
"request": "^2.81.0",
|
||||
"request-promise-native": "^1.0.4",
|
||||
"shx": "^0.2.2",
|
||||
"source-map-support": "^0.4.15",
|
||||
"tslint": "^5.3.2",
|
||||
"tslint-config-0xproject": "^0.0.2",
|
||||
"typedoc": "^0.7.1",
|
||||
"typescript": "^2.3.3",
|
||||
"web3-provider-engine": "^12.1.0",
|
||||
"web3-typescript-typings": "0.0.8",
|
||||
"webpack": "^2.6.0"
|
||||
},
|
||||
|
5
src/ts/globals.d.ts
vendored
5
src/ts/globals.d.ts
vendored
@ -1,5 +1,8 @@
|
||||
declare module 'chai-bignumber';
|
||||
declare module 'bn.js';
|
||||
declare module 'request-promise-native';
|
||||
declare module 'web3-provider-engine';
|
||||
declare module 'web3-provider-engine/subproviders/rpc';
|
||||
|
||||
declare interface Schema {
|
||||
id: string;
|
||||
@ -12,6 +15,7 @@ declare interface Schema {
|
||||
declare namespace Chai {
|
||||
interface Assertion {
|
||||
bignumber: Assertion;
|
||||
eventually: Assertion;
|
||||
}
|
||||
}
|
||||
/* tslint:enable */
|
||||
@ -30,6 +34,7 @@ declare module 'ethereumjs-util' {
|
||||
const ecrecover: (msgHashBuff: Buffer, v: number, r: Buffer, s: Buffer) => string;
|
||||
const pubToAddress: (pubKey: string) => Buffer;
|
||||
const isValidAddress: (address: string) => boolean;
|
||||
const bufferToInt: (buffer: Buffer) => number;
|
||||
}
|
||||
|
||||
// truffle-contract declarations
|
||||
|
99
test/contract_wrapper_test.ts
Normal file
99
test/contract_wrapper_test.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import 'mocha';
|
||||
import * as chai from 'chai';
|
||||
import chaiAsPromised = require('chai-as-promised');
|
||||
import {web3Factory} from './utils/web3_factory';
|
||||
import * as Web3 from 'web3';
|
||||
import {ExchangeWrapper} from '../src/ts/contract_wrappers/exchange_wrapper';
|
||||
import {BlockchainClean} from './utils/blockchain_clean';
|
||||
import {Web3Wrapper} from './../src/ts/web3_wrapper';
|
||||
|
||||
const expect = chai.expect;
|
||||
chai.use(chaiAsPromised);
|
||||
const blockchainClean = new BlockchainClean();
|
||||
|
||||
describe('ExchangeWrapper', () => {
|
||||
let web3Wrapper: Web3Wrapper;
|
||||
let exchangeWrapper: ExchangeWrapper;
|
||||
before(async () => {
|
||||
const web3 = web3Factory.create();
|
||||
web3Wrapper = new Web3Wrapper(web3);
|
||||
exchangeWrapper = new ExchangeWrapper(web3Wrapper);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainClean.setupAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainClean.restoreAsync();
|
||||
});
|
||||
describe('#isValidSignatureAsync', () => {
|
||||
// The Exchange smart contract `isValidSignature` method only validates orderHashes and assumes
|
||||
// the length of the data is exactly 32 bytes. Thus for these tests, we use data of this size.
|
||||
const dataHex = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
|
||||
const signature = {
|
||||
v: 27,
|
||||
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||
};
|
||||
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
||||
describe('should throw if passed a malformed signature', () => {
|
||||
it('malformed v', async () => {
|
||||
const malformedSignature = {
|
||||
v: 34,
|
||||
r: signature.r,
|
||||
s: signature.s,
|
||||
};
|
||||
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
|
||||
.to.be.rejected;
|
||||
});
|
||||
it('r lacks 0x prefix', () => {
|
||||
const malformedR = signature.r.replace('0x', '');
|
||||
const malformedSignature = {
|
||||
v: signature.v,
|
||||
r: malformedR,
|
||||
s: signature.s,
|
||||
};
|
||||
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
|
||||
.to.be.rejected;
|
||||
});
|
||||
it('r is too short', () => {
|
||||
const malformedR = signature.r.substr(10);
|
||||
const malformedSignature = {
|
||||
v: signature.v,
|
||||
r: malformedR,
|
||||
s: signature.s.replace('0', 'z'),
|
||||
};
|
||||
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
|
||||
.to.be.rejected;
|
||||
});
|
||||
it('s is not hex', () => {
|
||||
const malformedS = signature.s.replace('0', 'z');
|
||||
const malformedSignature = {
|
||||
v: signature.v,
|
||||
r: signature.r,
|
||||
s: malformedS,
|
||||
};
|
||||
expect(exchangeWrapper.isValidSignatureAsync(dataHex, malformedSignature, address))
|
||||
.to.be.rejected;
|
||||
});
|
||||
});
|
||||
it('should return false if the data doesn\'t pertain to the signature & address', async () => {
|
||||
const isValid = await exchangeWrapper.isValidSignatureAsync('0x0', signature, address);
|
||||
expect(isValid).to.be.false;
|
||||
});
|
||||
it('should return false if the address doesn\'t pertain to the signature & dataHex', async () => {
|
||||
const validUnrelatedAddress = '0x8b0292B11a196601eD2ce54B665CaFEca0347D42';
|
||||
const isValid = await exchangeWrapper.isValidSignatureAsync(dataHex, signature, validUnrelatedAddress);
|
||||
expect(isValid).to.be.false;
|
||||
});
|
||||
it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => {
|
||||
const wrongSignature = Object.assign({}, signature, {v: 28});
|
||||
const isValid = await exchangeWrapper.isValidSignatureAsync(dataHex, wrongSignature, address);
|
||||
expect(isValid).to.be.false;
|
||||
});
|
||||
it('should return true if the signature does pertain to the dataHex & address', async () => {
|
||||
const isValid = await exchangeWrapper.isValidSignatureAsync(dataHex, signature, address);
|
||||
console.log('isValid', isValid);
|
||||
expect(isValid).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
19
test/utils/blockchain_clean.ts
Normal file
19
test/utils/blockchain_clean.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import {RPC} from './rpc';
|
||||
|
||||
export class BlockchainClean {
|
||||
private rpc: RPC;
|
||||
private snapshotId: number;
|
||||
constructor() {
|
||||
this.rpc = new RPC();
|
||||
}
|
||||
// TODO: Check if running on TestRPC or on actual node, if actual node, re-deploy contracts instead
|
||||
public async setupAsync() {
|
||||
this.snapshotId = await this.rpc.takeSnapshotAsync();
|
||||
}
|
||||
public async restoreAsync() {
|
||||
const didRevert = await this.rpc.revertSnapshotAsync(this.snapshotId);
|
||||
if (!didRevert) {
|
||||
throw new Error(`Snapshot with id #${this.snapshotId} failed to revert`);
|
||||
}
|
||||
}
|
||||
};
|
5
test/utils/constants.ts
Normal file
5
test/utils/constants.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const constants = {
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
RPC_HOST: 'localhost',
|
||||
RPC_PORT: 8545,
|
||||
};
|
48
test/utils/rpc.ts
Normal file
48
test/utils/rpc.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as request from 'request-promise-native';
|
||||
import {constants} from './constants';
|
||||
|
||||
export class RPC {
|
||||
private host: string;
|
||||
private port: number;
|
||||
private id: number;
|
||||
constructor() {
|
||||
this.host = constants.RPC_HOST;
|
||||
this.port = constants.RPC_PORT;
|
||||
this.id = 0;
|
||||
}
|
||||
public async takeSnapshotAsync(): Promise<number> {
|
||||
const method = 'evm_snapshot';
|
||||
const params: any[] = [];
|
||||
const payload = this.toPayload(method, params);
|
||||
const snapshotIdHex = await this.sendAsync(payload);
|
||||
const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex));
|
||||
return snapshotId;
|
||||
}
|
||||
public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
|
||||
const method = 'evm_revert';
|
||||
const params = [snapshotId];
|
||||
const payload = this.toPayload(method, params);
|
||||
const didRevert = await this.sendAsync(payload);
|
||||
return didRevert;
|
||||
}
|
||||
private toPayload(method: string, params: any[] = []) {
|
||||
const payload = JSON.stringify({
|
||||
id: this.id,
|
||||
method,
|
||||
params,
|
||||
});
|
||||
this.id += 1;
|
||||
return payload;
|
||||
}
|
||||
private async sendAsync(payload: string) {
|
||||
const opts = {
|
||||
method: 'POST',
|
||||
uri: `http://${this.host}:${this.port}`,
|
||||
body: payload,
|
||||
};
|
||||
const bodyString = await request(opts);
|
||||
const body = JSON.parse(bodyString);
|
||||
return body.result;
|
||||
}
|
||||
}
|
23
test/utils/web3_factory.ts
Normal file
23
test/utils/web3_factory.ts
Normal file
@ -0,0 +1,23 @@
|
||||
// HACK: web3 injects XMLHttpRequest into the global scope and ProviderEngine checks XMLHttpRequest
|
||||
// to know whether it is running in a browser or node environment. We need it to be undefined since
|
||||
// we are not running in a browser env.
|
||||
// Filed issue: https://github.com/ethereum/web3.js/issues/844
|
||||
(global as any).XMLHttpRequest = undefined;
|
||||
import ProviderEngine = require('web3-provider-engine');
|
||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
||||
import * as Web3 from 'web3';
|
||||
import {constants} from './constants';
|
||||
|
||||
export const web3Factory = {
|
||||
create(): Web3 {
|
||||
const provider = new ProviderEngine();
|
||||
const rpcUrl = `http://${constants.RPC_HOST}:${constants.RPC_PORT}`;
|
||||
provider.addProvider(new RpcSubprovider({
|
||||
rpcUrl,
|
||||
}));
|
||||
provider.start();
|
||||
const web3 = new Web3();
|
||||
web3.setProvider(provider);
|
||||
return web3;
|
||||
},
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user