Fix TSLint rules

This commit is contained in:
Fabio Berger 2018-05-16 14:59:10 +02:00
parent fec6ac3ff0
commit 839db68571
55 changed files with 278 additions and 133 deletions

View File

@ -1,9 +1,23 @@
const networkNameToId: { [networkName: string]: number } = {
mainnet: 1,
ropsten: 3,
rinkeby: 4,
kovan: 42,
ganache: 50,
};
export const zeroExPublicNetworkConfigSchema = {
id: '/ZeroExPublicNetworkConfig',
properties: {
networkId: {
type: 'number',
enum: [1, 3, 4, 42, 50],
enum: [
networkNameToId.mainnet,
networkNameToId.ropsten,
networkNameToId.rinkeby,
networkNameToId.kovan,
networkNameToId.ganache,
],
},
gasPrice: { $ref: '/Number' },
zrxContractAddress: { $ref: '/Address' },

View File

@ -8,7 +8,8 @@ import { provider } from './utils/web3_wrapper';
before('migrate contracts', async function(): Promise<void> {
// HACK: Since the migrations take longer then our global mocha timeout limit
// we manually increase it for this before hook.
this.timeout(20000);
const mochaTestTimeoutMs = 20000;
this.timeout(mochaTestTimeoutMs);
const txDefaults = {
gas: devConstants.GAS_ESTIMATE,
from: devConstants.TESTRPC_FIRST_ADDRESS,

View File

@ -10,6 +10,7 @@ chai.config.includeStack = true;
chai.use(dirtyChai);
const expect = chai.expect;
// tslint:disable:custom-no-magic-numbers
describe('Assertions', () => {
const variableName = 'variable';
describe('#isBigNumber', () => {
@ -251,3 +252,4 @@ describe('Assertions', () => {
});
});
});
// tslint:enable:custom-no-magic-numbers

View File

@ -1,9 +1,23 @@
const networkNameToId: { [networkName: string]: number } = {
mainnet: 1,
ropsten: 3,
rinkeby: 4,
kovan: 42,
ganache: 50,
};
export const contractWrappersPublicNetworkConfigSchema = {
id: '/ZeroExContractPublicNetworkConfig',
properties: {
networkId: {
type: 'number',
enum: [1, 3, 4, 42, 50],
enum: [
networkNameToId.mainnet,
networkNameToId.kovan,
networkNameToId.ropsten,
networkNameToId.rinkeby,
networkNameToId.ganache,
],
},
gasPrice: { $ref: '/Number' },
zrxContractAddress: { $ref: '/Address' },

View File

@ -6,6 +6,7 @@ export const constants = {
INVALID_JUMP_PATTERN: 'invalid JUMP at',
OUT_OF_GAS_PATTERN: 'out of gas',
INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string',
// tslint:disable-next-line:custom-no-magic-numbers
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
};

View File

@ -73,14 +73,14 @@ export const filterUtils = {
return false;
}
if (!_.isUndefined(filter.topics)) {
return filterUtils.matchesTopics(log.topics, filter.topics);
return filterUtils.doesMatchTopics(log.topics, filter.topics);
}
return true;
},
matchesTopics(logTopics: string[], filterTopics: Array<string[] | string | null>): boolean {
doesMatchTopics(logTopics: string[], filterTopics: Array<string[] | string | null>): boolean {
const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
const matchesTopics = _.every(matchesTopic);
return matchesTopics;
const doesMatchTopics = _.every(matchesTopic);
return doesMatchTopics;
},
matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean {
if (_.isArray(filterTopic)) {

View File

@ -5,7 +5,8 @@ export const utils = {
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
},
getCurrentUnixTimestampSec(): BigNumber {
return new BigNumber(Date.now() / 1000).round();
const milisecondsInSecond = 1000;
return new BigNumber(Date.now() / milisecondsInSecond).round();
},
getCurrentUnixTimestampMs(): BigNumber {
return new BigNumber(Date.now());

View File

@ -41,7 +41,7 @@ describe('EtherTokenWrapper', () => {
let addressWithETH: string;
let wethContractAddress: string;
let depositWeiAmount: BigNumber;
let decimalPlaces: number;
const decimalPlaces = 7;
let addressWithoutFunds: string;
const gasPrice = new BigNumber(1);
const zeroExConfig = {
@ -59,7 +59,6 @@ describe('EtherTokenWrapper', () => {
addressWithETH = userAddresses[0];
wethContractAddress = contractWrappers.etherToken.getContractAddressIfExists() as string;
depositWeiAmount = Web3Wrapper.toWei(new BigNumber(5));
decimalPlaces = 7;
addressWithoutFunds = userAddresses[1];
});
beforeEach(async () => {
@ -154,6 +153,7 @@ describe('EtherTokenWrapper', () => {
const preWETHBalance = await contractWrappers.token.getBalanceAsync(wethContractAddress, addressWithETH);
expect(preWETHBalance).to.be.bignumber.equal(0);
// tslint:disable-next-line:custom-no-magic-numbers
const overWETHBalance = preWETHBalance.add(999999999);
return expect(

View File

@ -8,7 +8,8 @@ import { provider } from './utils/web3_wrapper';
before('migrate contracts', async function(): Promise<void> {
// HACK: Since the migrations take longer then our global mocha timeout limit
// we manually increase it for this before hook.
this.timeout(20000);
const mochaTestTimeoutMs = 20000;
this.timeout(mochaTestTimeoutMs);
const txDefaults = {
gas: devConstants.GAS_ESTIMATE,
from: devConstants.TESTRPC_FIRST_ADDRESS,

View File

@ -105,6 +105,7 @@ describe('OrderValidation', () => {
});
it('should succeed if the order is asymmetric and fillable', async () => {
const makerFillableAmount = fillableAmount;
// tslint:disable-next-line:custom-no-magic-numbers
const takerFillableAmount = fillableAmount.minus(4);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress,
@ -171,6 +172,7 @@ describe('OrderValidation', () => {
fillableAmount,
);
// 27 <--> 28
// tslint:disable-next-line:custom-no-magic-numbers
signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
return expect(
contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync(
@ -205,7 +207,8 @@ describe('OrderValidation', () => {
takerAddress,
fillableAmount,
);
const nonTakerAddress = userAddresses[6];
const sixthIndex = 6;
const nonTakerAddress = userAddresses[sixthIndex];
return expect(
contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder,
@ -352,7 +355,8 @@ describe('OrderValidation', () => {
takerAddress,
zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
const expectedCallCount = 4;
expect(transferFromAsync.callCount).to.be.equal(expectedCallCount);
expect(
transferFromAsync
.getCall(0)
@ -422,7 +426,8 @@ describe('OrderValidation', () => {
takerAddress,
zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
const expectedCallCount = 4;
expect(transferFromAsync.callCount).to.be.equal(expectedCallCount);
expect(
transferFromAsync
.getCall(0)
@ -490,7 +495,8 @@ describe('OrderValidation', () => {
takerAddress,
zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
const expectedCallCount = 4;
expect(transferFromAsync.callCount).to.be.equal(expectedCallCount);
const makerFillAmount = transferFromAsync.getCall(0).args[3];
expect(makerFillAmount).to.be.bignumber.equal(makerTokenAmount);
});
@ -517,7 +523,8 @@ describe('OrderValidation', () => {
);
const makerPartialFee = makerFee.div(2);
const takerPartialFee = takerFee.div(2);
expect(transferFromAsync.callCount).to.be.equal(4);
const expectedCallCount = 4;
expect(transferFromAsync.callCount).to.be.equal(expectedCallCount);
const partialMakerFee = transferFromAsync.getCall(2).args[3];
expect(partialMakerFee).to.be.bignumber.equal(makerPartialFee);
const partialTakerFee = transferFromAsync.getCall(3).args[3];

View File

@ -123,21 +123,21 @@ describe('Exchange', () => {
});
it('should return true with a valid signature', async () => {
const success = await exchangeWrapper.isValidSignatureAsync(signedOrder);
const isValidSignatureForContract = await exchangeWrapper.isValidSignatureAsync(signedOrder);
const orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, signedOrder.ecSignature, signedOrder.maker);
expect(isValidSignature).to.be.true();
expect(success).to.be.true();
expect(isValidSignatureForContract).to.be.true();
});
it('should return false with an invalid signature', async () => {
signedOrder.ecSignature.r = ethUtil.bufferToHex(ethUtil.sha3('invalidR'));
signedOrder.ecSignature.s = ethUtil.bufferToHex(ethUtil.sha3('invalidS'));
const success = await exchangeWrapper.isValidSignatureAsync(signedOrder);
const isValidSignatureForContract = await exchangeWrapper.isValidSignatureAsync(signedOrder);
const orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, signedOrder.ecSignature, signedOrder.maker);
expect(isValidSignature).to.be.false();
expect(success).to.be.false();
expect(isValidSignatureForContract).to.be.false();
});
});

View File

@ -99,8 +99,8 @@ describe('UnlimitedAllowanceToken', () => {
const amountToTransfer = ownerBalance;
const spenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender);
const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
expect(spenderAllowanceIsInsufficient).to.be.true();
const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
expect(isSpenderAllowanceInsufficient).to.be.true();
return expect(
token.transferFrom.callAsync(owner, spender, amountToTransfer, {

View File

@ -117,8 +117,8 @@ describe('ZRXToken', () => {
const amountToTransfer = ownerBalance;
const spenderAllowance = await zeroEx.token.getAllowanceAsync(zrxAddress, owner, spender);
const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
expect(spenderAllowanceIsInsufficient).to.be.true();
const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
expect(isSpenderAllowanceInsufficient).to.be.true();
const didReturnTrue = await zrx.transferFrom.callAsync(owner, spender, amountToTransfer, { from: spender });
expect(didReturnTrue).to.be.false();

View File

@ -1,3 +1,6 @@
{
"extends": ["@0xproject/tslint-config"]
"extends": ["@0xproject/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@ -148,7 +148,8 @@ describe('Schema', () => {
});
describe('#blockParamSchema', () => {
it('should validate valid block param', () => {
const testCases = [42, 'latest', 'pending', 'earliest'];
const blockNumber = 42;
const testCases = [blockNumber, 'latest', 'pending', 'earliest'];
validateAgainstSchema(testCases, blockParamSchema);
});
it('should fail for invalid block param', () => {
@ -181,6 +182,7 @@ describe('Schema', () => {
validateAgainstSchema(testCases, tokenSchema);
});
it('should fail for invalid token', () => {
const num = 4;
const testCases = [
{
...token,
@ -191,7 +193,7 @@ describe('Schema', () => {
decimals: undefined,
},
[],
4,
num,
];
const shouldFail = true;
validateAgainstSchema(testCases, tokenSchema, shouldFail);
@ -870,10 +872,12 @@ describe('Schema', () => {
});
describe('#jsNumberSchema', () => {
it('should validate valid js number', () => {
// tslint:disable-next-line:custom-no-magic-numbers
const testCases = [1, 42];
validateAgainstSchema(testCases, jsNumber);
});
it('should fail for invalid js number', () => {
// tslint:disable-next-line:custom-no-magic-numbers
const testCases = [NaN, -1, new BigNumber(1)];
const shouldFail = true;
validateAgainstSchema(testCases, jsNumber, shouldFail);
@ -881,13 +885,14 @@ describe('Schema', () => {
});
describe('#txDataSchema', () => {
it('should validate valid txData', () => {
const bigNumGasAmt = new BigNumber(42);
const testCases = [
{
from: NULL_ADDRESS,
},
{
from: NULL_ADDRESS,
gas: new BigNumber(42),
gas: bigNumGasAmt,
},
{
from: NULL_ADDRESS,

View File

@ -80,11 +80,12 @@ export const runMigrationsAsync = async (provider: Provider, artifactsDir: strin
tokenInfo[0].swarmHash,
{ from: owner },
);
const decimals = 18;
await tokenReg.addToken.sendTransactionAsync(
zrxToken.address,
'0x Protocol Token',
'ZRX',
18,
decimals,
NULL_BYTES,
NULL_BYTES,
{
@ -96,7 +97,7 @@ export const runMigrationsAsync = async (provider: Provider, artifactsDir: strin
etherToken.address,
'Ether Token',
'WETH',
18,
decimals,
NULL_BYTES,
NULL_BYTES,
{

View File

@ -158,6 +158,7 @@ export const postpublishUtils = {
// HACK: tsconfig.json needs wildcard directory endings as `/**/*`
// but TypeDoc needs it as `/**` in order to pick up files at the root
if (_.endsWith(includePath, '/**/*')) {
// tslint:disable-next-line:custom-no-magic-numbers
includePath = includePath.slice(0, -2);
}
return includePath;

View File

@ -285,8 +285,8 @@ function shouldAddNewChangelogEntry(currentVersion: string, changelogs: Changelo
return true;
}
const lastEntry = changelogs[0];
const lastEntryCurrentVersion = lastEntry.version === currentVersion;
return lastEntryCurrentVersion;
const isLastEntryCurrentVersion = lastEntry.version === currentVersion;
return isLastEntryCurrentVersion;
}
function generateChangelogMd(changelogs: Changelog[]): string {

View File

@ -17,7 +17,8 @@ const INVALID_TAKER_FORMAT = 'instance.taker is not of a type(s) string';
* We do not use BN anywhere else in the codebase.
*/
function bigNumberToBN(value: BigNumber): BN {
return new BN(value.toString(), 10);
const base = 10;
return new BN(value.toString(), base);
}
/**

View File

@ -72,6 +72,7 @@ export async function signOrderHashAsync(
// v + r + s OR r + s + v, and different clients (even different versions of the same client)
// return the signature params in different orders. In order to support all client implementations,
// we parse the signature in both ways, and evaluate if either one is a valid signature.
// tslint:disable-next-line:custom-no-magic-numbers
const validVParamValues = [27, 28];
const ecSignatureVRS = parseSignatureHexAsVRS(signature);
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
@ -95,11 +96,19 @@ export async function signOrderHashAsync(
function parseSignatureHexAsVRS(signatureHex: string): ECSignature {
const signatureBuffer = ethUtil.toBuffer(signatureHex);
let v = signatureBuffer[0];
if (v < 27) {
v += 27;
// HACK: Sometimes v is returned as [0, 1] and sometimes as [27, 28]
// If it is returned as [0, 1], add 27 to both so it becomes [27, 28]
const lowestValidV = 27;
const isProperlyFormattedV = v < lowestValidV;
if (!isProperlyFormattedV) {
v += lowestValidV;
}
const r = signatureBuffer.slice(1, 33);
const s = signatureBuffer.slice(33, 65);
// signatureBuffer contains vrs
const vEndIndex = 1;
const rsIndex = 33;
const r = signatureBuffer.slice(vEndIndex, rsIndex);
const sEndIndex = 65;
const s = signatureBuffer.slice(rsIndex, sEndIndex);
const ecSignature: ECSignature = {
v,
r: ethUtil.bufferToHex(r),

View File

@ -46,12 +46,13 @@ describe('Signature utils', () => {
});
describe('#generateSalt', () => {
it('generates different salts', () => {
const equal = generatePseudoRandomSalt().eq(generatePseudoRandomSalt());
expect(equal).to.be.false();
const isEqual = generatePseudoRandomSalt().eq(generatePseudoRandomSalt());
expect(isEqual).to.be.false();
});
it('generates salt in range [0..2^256)', () => {
const salt = generatePseudoRandomSalt();
expect(salt.greaterThanOrEqualTo(0)).to.be.true();
// tslint:disable-next-line:custom-no-magic-numbers
const twoPow256 = new BigNumber(2).pow(256);
expect(salt.lessThan(twoPow256)).to.be.true();
});
@ -66,7 +67,8 @@ describe('Signature utils', () => {
expect(isValid).to.be.false();
});
it('returns true if order hash is correct', () => {
const isValid = isValidOrderHash('0x' + Array(65).join('0'));
const orderHashLength = 65;
const isValid = isValidOrderHash('0x' + Array(orderHashLength).join('0'));
expect(isValid).to.be.true();
});
});
@ -110,10 +112,12 @@ describe('Signature utils', () => {
if (payload.method === 'eth_sign') {
const [address, message] = payload.params;
const signature = await web3Wrapper.signMessageAsync(address, message);
// tslint:disable-next-line:custom-no-magic-numbers
const rsvHex = `0x${signature.substr(130)}${signature.substr(2, 128)}`;
callback(null, {
id: 42,
jsonrpc: '2.0',
result: `0x${signature.substr(130)}${signature.substr(2, 128)}`,
result: rsvHex,
});
} else {
callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] });

View File

@ -60,6 +60,7 @@ interface OrderStateByOrderHash {
[orderHash: string]: OrderState;
}
// tslint:disable-next-line:custom-no-magic-numbers
const DEFAULT_CLEANUP_JOB_INTERVAL_MS = 1000 * 60 * 60; // 1h
/**
@ -130,7 +131,8 @@ export class OrderWatcher {
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
this._orderByOrderHash[orderHash] = signedOrder;
this._addToDependentOrderHashes(signedOrder, orderHash);
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
const milisecondsInASecond = 1000;
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(milisecondsInASecond);
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
}
/**

View File

@ -5,7 +5,8 @@ export const utils = {
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
},
getCurrentUnixTimestampSec(): BigNumber {
return new BigNumber(Date.now() / 1000).round();
const milisecondsInASecond = 1000;
return new BigNumber(Date.now() / milisecondsInASecond).round();
},
getCurrentUnixTimestampMs(): BigNumber {
return new BigNumber(Date.now());

View File

@ -21,6 +21,7 @@ import { provider, web3Wrapper } from './utils/web3_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const MILISECONDS_IN_SECOND = 1000;
describe('ExpirationWatcher', () => {
let contractWrappers: ContractWrappers;
@ -83,13 +84,13 @@ describe('ExpirationWatcher', () => {
expirationUnixTimestampSec,
);
const orderHash = getOrderHashHex(signedOrder);
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND));
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)((hash: string) => {
expect(hash).to.be.equal(orderHash);
expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
});
expirationWatcher.subscribe(callbackAsync);
timer.tick(orderLifetimeSec * 1000);
timer.tick(orderLifetimeSec * MILISECONDS_IN_SECOND);
})().catch(done);
});
it("doesn't emit events before order expires", (done: DoneCallback) => {
@ -105,13 +106,13 @@ describe('ExpirationWatcher', () => {
expirationUnixTimestampSec,
);
const orderHash = getOrderHashHex(signedOrder);
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND));
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)(async (hash: string) => {
done(new Error('Emitted expiration went before the order actually expired'));
});
expirationWatcher.subscribe(callbackAsync);
const notEnoughTime = orderLifetimeSec - 1;
timer.tick(notEnoughTime * 1000);
timer.tick(notEnoughTime * MILISECONDS_IN_SECOND);
done();
})().catch(done);
});
@ -139,8 +140,14 @@ describe('ExpirationWatcher', () => {
);
const orderHash1 = getOrderHashHex(signedOrder1);
const orderHash2 = getOrderHashHex(signedOrder2);
expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
expirationWatcher.addOrder(
orderHash2,
signedOrder2.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND),
);
expirationWatcher.addOrder(
orderHash1,
signedOrder1.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND),
);
const expirationOrder = [orderHash1, orderHash2];
const expectToBeCalledOnce = false;
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
@ -153,7 +160,7 @@ describe('ExpirationWatcher', () => {
},
);
expirationWatcher.subscribe(callbackAsync);
timer.tick(order2Lifetime * 1000);
timer.tick(order2Lifetime * MILISECONDS_IN_SECOND);
})().catch(done);
});
it('emits events in correct order when expirations are equal', (done: DoneCallback) => {
@ -180,8 +187,14 @@ describe('ExpirationWatcher', () => {
);
const orderHash1 = getOrderHashHex(signedOrder1);
const orderHash2 = getOrderHashHex(signedOrder2);
expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
expirationWatcher.addOrder(
orderHash1,
signedOrder1.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND),
);
expirationWatcher.addOrder(
orderHash2,
signedOrder2.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND),
);
const expirationOrder = orderHash1 < orderHash2 ? [orderHash1, orderHash2] : [orderHash2, orderHash1];
const expectToBeCalledOnce = false;
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
@ -194,7 +207,7 @@ describe('ExpirationWatcher', () => {
},
);
expirationWatcher.subscribe(callbackAsync);
timer.tick(order2Lifetime * 1000);
timer.tick(order2Lifetime * MILISECONDS_IN_SECOND);
})().catch(done);
});
});

View File

@ -8,7 +8,8 @@ import { provider } from './utils/web3_wrapper';
before('migrate contracts', async function(): Promise<void> {
// HACK: Since the migrations take longer then our global mocha timeout limit
// we manually increase it for this before hook.
this.timeout(20000);
const mochaTestTimeoutMs = 20000;
this.timeout(mochaTestTimeoutMs);
const txDefaults = {
gas: devConstants.GAS_ESTIMATE,
from: devConstants.TESTRPC_FIRST_ADDRESS,

View File

@ -268,8 +268,8 @@ describe('OrderWatcher', () => {
});
it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
(async () => {
const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18);
const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18);
const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals);
const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals);
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerToken.address,
takerToken.address,

View File

@ -64,8 +64,8 @@ export class DocsInfo {
finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => {
const versionIntroducedIfExists = this._docsInfo.menuSubsectionToVersionWhenIntroduced[contractName];
if (!_.isUndefined(versionIntroducedIfExists)) {
const existsInSelectedVersion = compareVersions(selectedVersion, versionIntroducedIfExists) >= 0;
return existsInSelectedVersion;
const doesExistInSelectedVersion = compareVersions(selectedVersion, versionIntroducedIfExists) >= 0;
return doesExistInSelectedVersion;
} else {
return true;
}

View File

@ -3,6 +3,7 @@
"rules": {
"no-object-literal-type-assertion": false,
"completed-docs": false,
"prefer-function-over-method": false
"prefer-function-over-method": false,
"custom-no-magic-numbers": false
}
}

View File

@ -3,6 +3,7 @@
"rules": {
"no-object-literal-type-assertion": false,
"completed-docs": false,
"prefer-function-over-method": false
"prefer-function-over-method": false,
"custom-no-magic-numbers": false
}
}

View File

@ -152,7 +152,8 @@ export class Compiler {
logUtils.log(`Downloading ${fullSolcVersion}...`);
const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`;
const response = await fetch(url);
if (response.status !== 200) {
const SUCCESS_STATUS = 200;
if (response.status !== SUCCESS_STATUS) {
throw new Error(`Failed to load ${fullSolcVersion}`);
}
solcjs = await response.text();

View File

@ -38,8 +38,12 @@ describe('#Compiler', function(): void {
const exchangeArtifactString = await fsWrapper.readFileAsync(exchangeArtifactPath, opts);
const exchangeArtifact: ContractArtifact = JSON.parse(exchangeArtifactString);
// The last 43 bytes of the binaries are metadata which may not be equivalent
const unlinkedBinaryWithoutMetadata = exchangeArtifact.compilerOutput.evm.bytecode.object.slice(2, -86);
const exchangeBinaryWithoutMetadata = exchange_binary.slice(0, -86);
const last43BytesIndex = -86;
const unlinkedBinaryWithoutMetadata = exchangeArtifact.compilerOutput.evm.bytecode.object.slice(
2,
last43BytesIndex,
);
const exchangeBinaryWithoutMetadata = exchange_binary.slice(0, last43BytesIndex);
expect(unlinkedBinaryWithoutMetadata).to.equal(exchangeBinaryWithoutMetadata);
});
});

View File

@ -39,13 +39,15 @@ describe('Collect coverage entries', () => {
const coverageEntries = collectCoverageEntries(simpleStorageContract);
const fnIds = _.keys(coverageEntries.fnMap);
expect(coverageEntries.fnMap[fnIds[0]].name).to.be.equal('set');
expect(coverageEntries.fnMap[fnIds[0]].line).to.be.equal(5);
const setExpectedLineNumber = 5;
expect(coverageEntries.fnMap[fnIds[0]].line).to.be.equal(setExpectedLineNumber);
const setFunction = `function set(uint x) {
storedData = x;
}`;
expect(getRange(simpleStorageContract, coverageEntries.fnMap[fnIds[0]].loc)).to.be.equal(setFunction);
expect(coverageEntries.fnMap[fnIds[1]].name).to.be.equal('get');
expect(coverageEntries.fnMap[fnIds[1]].line).to.be.equal(8);
const getExpectedLineNumber = 8;
expect(coverageEntries.fnMap[fnIds[1]].line).to.be.equal(getExpectedLineNumber);
const getFunction = `function get() constant returns (uint retVal) {
return storedData;
}`;
@ -121,6 +123,7 @@ describe('Collect coverage entries', () => {
const branchDescriptions = _.values(coverageEntries.branchMap);
const branchLines = _.map(branchDescriptions, branchDescription => branchDescription.line);
// tslint:disable-next-line:custom-no-magic-numbers
expect(branchLines).to.be.deep.equal([94, 115, 119, 130, 151, 187]);
const branchTypes = _.map(branchDescriptions, branchDescription => branchDescription.type);
expect(branchTypes).to.be.deep.equal(['if', 'if', 'if', 'if', 'binary-expr', 'if']);

View File

@ -11,6 +11,7 @@ const expect = chai.expect;
describe('instructions', () => {
describe('#getPcToInstructionIndexMapping', () => {
it('correctly maps pcs to instruction indexed', () => {
// tslint:disable-next-line:custom-no-magic-numbers
const bytecode = new Uint8Array([constants.PUSH1, 42, constants.PUSH2, 1, 2, constants.TIMESTAMP]);
const pcToInstruction = getPcToInstructionIndexMapping(bytecode);
const expectedPcToInstruction = { '0': 0, '2': 1, '5': 2 };

View File

@ -13,7 +13,18 @@ import { postmanEnvironmentFactory } from './postman_environment_factory';
import { utils } from './utils';
const DEFAULT_NETWORK_ID = 1;
const SUPPORTED_NETWORK_IDS = [1, 3, 4, 42];
const networkNameToId: { [networkName: string]: number } = {
mainnet: 1,
ropsten: 3,
rinkeby: 4,
kovan: 42,
};
const SUPPORTED_NETWORK_IDS = [
networkNameToId.mainnet,
networkNameToId.ropsten,
networkNameToId.rinkeby,
networkNameToId.kovan,
];
// extract command line arguments
const args = yargs

View File

@ -11,6 +11,12 @@ import { addresses as rinkebyAddresses } from './contract_addresses/rinkeby_addr
import { addresses as ropstenAddresses } from './contract_addresses/ropsten_addresses';
const ENVIRONMENT_NAME = 'SRA Report';
const networkNameToId: { [networkName: string]: number } = {
mainnet: 1,
ropsten: 3,
rinkeby: 4,
kovan: 42,
};
export interface EnvironmentValue {
key: string;
@ -107,13 +113,13 @@ async function createOrderEnvironmentValuesAsync(url: string): Promise<Environme
}
function getContractAddresses(networkId: number): Addresses {
switch (networkId) {
case 1:
case networkNameToId.mainnet:
return mainnetAddresses;
case 3:
case networkNameToId.ropsten:
return ropstenAddresses;
case 4:
case networkNameToId.rinkeby:
return rinkebyAddresses;
case 42:
case networkNameToId.kovan:
return kovanAddresses;
default:
throw new Error('Unsupported network id');

View File

@ -23,6 +23,7 @@ const expect = chai.expect;
const CONTENT_TYPE_ASSERTION_NAME = 'Has Content-Type header with value application/json';
const SCHEMA_ASSERTION_NAME = 'Schema is valid';
const SUCCESS_STATUS = 200;
const baseNewmanRunOptions = {
collection: sraReportCollectionJSON,
environment: postmanEnvironmentJSON,
@ -45,7 +46,7 @@ export const testRunner = {
};
describe(CONTENT_TYPE_ASSERTION_NAME, () => {
it('fails when there are no headers', async () => {
nockInterceptor.reply(200, {});
nockInterceptor.reply(SUCCESS_STATUS, {});
const summary = await utils.newmanRunAsync(newmanRunOptions);
const error = findAssertionErrorIfExists(
summary,
@ -60,7 +61,7 @@ export const testRunner = {
const headers = {
'Content-Type': 'text/html',
};
nockInterceptor.reply(200, {}, headers);
nockInterceptor.reply(SUCCESS_STATUS, {}, headers);
const summary = await utils.newmanRunAsync(newmanRunOptions);
const error = findAssertionErrorIfExists(
summary,
@ -75,7 +76,7 @@ export const testRunner = {
const headers = {
'Content-Type': 'charset=utf-8; application/json',
};
nockInterceptor.reply(200, {}, headers);
nockInterceptor.reply(SUCCESS_STATUS, {}, headers);
const summary = await utils.newmanRunAsync(newmanRunOptions);
const error = findAssertionErrorIfExists(
summary,
@ -99,7 +100,7 @@ export const testRunner = {
};
describe(SCHEMA_ASSERTION_NAME, () => {
it('fails when schema is invalid', async () => {
nockInterceptor.reply(200, malformedJson);
nockInterceptor.reply(SUCCESS_STATUS, malformedJson);
const summary = await utils.newmanRunAsync(newmanRunOptions);
const error = findAssertionErrorIfExists(summary, postmanCollectionRequestName, SCHEMA_ASSERTION_NAME);
const errorMessage = _.get(error, 'message');
@ -107,7 +108,7 @@ export const testRunner = {
expect(errorMessage).to.equal('expected false to be true');
});
it('passes when schema is valid', async () => {
nockInterceptor.reply(200, correctJson);
nockInterceptor.reply(SUCCESS_STATUS, correctJson);
const summary = await utils.newmanRunAsync(newmanRunOptions);
const error = findAssertionErrorIfExists(summary, postmanCollectionRequestName, SCHEMA_ASSERTION_NAME);
const errorMessage = _.get(error, 'message');

View File

@ -113,9 +113,12 @@ export class LedgerSubprovider extends BaseWalletSubprovider {
const tx = new EthereumTx(txParams);
// Set the EIP155 bits
tx.raw[6] = Buffer.from([this._networkId]); // v
tx.raw[7] = Buffer.from([]); // r
tx.raw[8] = Buffer.from([]); // s
const vIndex = 6;
tx.raw[vIndex] = Buffer.from([this._networkId]); // v
const rIndex = 7;
tx.raw[rIndex] = Buffer.from([]); // r
const sIndex = 8;
tx.raw[sIndex] = Buffer.from([]); // s
const txHex = tx.serialize().toString('hex');
try {
@ -127,7 +130,8 @@ export class LedgerSubprovider extends BaseWalletSubprovider {
tx.v = Buffer.from(result.v, 'hex');
// EIP155: v should be chain_id * 2 + {35, 36}
const signedChainId = Math.floor((tx.v[0] - 35) / 2);
const eip55Constant = 35;
const signedChainId = Math.floor((tx.v[0] - eip55Constant) / 2);
if (signedChainId !== this._networkId) {
await this._destroyLedgerClientAsync();
const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware);
@ -169,8 +173,10 @@ export class LedgerSubprovider extends BaseWalletSubprovider {
fullDerivationPath,
ethUtil.stripHexPrefix(data),
);
const v = result.v - 27;
let vHex = v.toString(16);
const lowestValidV = 27;
const v = result.v - lowestValidV;
const hexBase = 16;
let vHex = v.toString(hexBase);
if (vHex.length < 2) {
vHex = `0${v}`;
}

View File

@ -93,7 +93,8 @@ export class NonceTrackerSubprovider extends Subprovider {
// Increment the nonce from the previous successfully submitted transaction
let nonce = ethUtil.bufferToInt(transaction.nonce);
nonce++;
let nextHexNonce = nonce.toString(16);
const hexBase = 16;
let nextHexNonce = nonce.toString(hexBase);
if (nextHexNonce.length % 2) {
nextHexNonce = `0${nextHexNonce}`;
}

View File

@ -13,10 +13,11 @@ export abstract class Subprovider {
// Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
private static _getRandomId(): number {
const extraDigits = 3;
const baseTen = 10;
// 13 time digits
const datePart = new Date().getTime() * Math.pow(10, extraDigits);
const datePart = new Date().getTime() * Math.pow(baseTen, extraDigits);
// 3 random digits
const extraPart = Math.floor(Math.random() * Math.pow(10, extraDigits));
const extraPart = Math.floor(Math.random() * Math.pow(baseTen, extraDigits));
// 16 digits
return datePart + extraPart;
}

View File

@ -30,10 +30,10 @@ class DerivedHDKeyInfoIterator implements IterableIterator<DerivedHDKeyInfo> {
baseDerivationPath,
derivationPath: fullDerivationPath,
};
const done = this._index === this._searchLimit;
const isDone = this._index === this._searchLimit;
this._index++;
return {
done,
done: isDone,
value: derivedKey,
};
}

View File

@ -19,6 +19,8 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
chaiSetup.configure();
const expect = chai.expect;
const DEFAULT_NUM_ACCOUNTS = 10;
const EXPECTED_SIGNATURE_LENGTH = 132;
async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumClient> {
const ledgerConnection = await TransportNodeHid.create();
@ -40,7 +42,7 @@ describe('LedgerSubprovider', () => {
it('returns default number of accounts', async () => {
const accounts = await ledgerSubprovider.getAccountsAsync();
expect(accounts[0]).to.not.be.an('undefined');
expect(accounts.length).to.be.equal(10);
expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
});
it('returns the expected accounts from a ledger set up with the test mnemonic', async () => {
const accounts = await ledgerSubprovider.getAccountsAsync();
@ -104,7 +106,7 @@ describe('LedgerSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.length).to.be.equal(10);
expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
done();
});
ledgerProvider.sendAsync(payload, callback);
@ -122,7 +124,7 @@ describe('LedgerSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.length).to.be.equal(132);
expect(response.result.length).to.be.equal(EXPECTED_SIGNATURE_LENGTH);
expect(response.result.substr(0, 2)).to.be.equal('0x');
done();
});
@ -142,7 +144,7 @@ describe('LedgerSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.length).to.be.equal(132);
expect(response.result.length).to.be.equal(EXPECTED_SIGNATURE_LENGTH);
expect(response.result.substr(0, 2)).to.be.equal('0x');
done();
});
@ -196,7 +198,8 @@ describe('LedgerSubprovider', () => {
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
const result = response.result;
expect(result.length).to.be.equal(66);
const signedTxLength = 66;
expect(result.length).to.be.equal(signedTxLength);
expect(result.substr(0, 2)).to.be.equal('0x');
done();
});

View File

@ -20,6 +20,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
chaiSetup.configure();
const expect = chai.expect;
const FAKE_ADDRESS = '0xb088a3bc93f71b4de97b9de773e9647645983688';
const DEFAULT_NUM_ACCOUNTS = 10;
describe('LedgerSubprovider', () => {
const networkId: number = 42;
@ -72,7 +73,7 @@ describe('LedgerSubprovider', () => {
it('returns default number of accounts', async () => {
const accounts = await ledgerSubprovider.getAccountsAsync();
expect(accounts[0]).to.be.equal(FAKE_ADDRESS);
expect(accounts.length).to.be.equal(10);
expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
});
it('returns requested number of accounts', async () => {
const numberOfAccounts = 20;
@ -118,7 +119,7 @@ describe('LedgerSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.length).to.be.equal(10);
expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
expect(response.result[0]).to.be.equal(FAKE_ADDRESS);
done();
});
@ -175,7 +176,8 @@ describe('LedgerSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.raw.length).to.be.equal(192);
const rawTxLength = 192;
expect(response.result.raw.length).to.be.equal(rawTxLength);
expect(response.result.raw.substr(0, 2)).to.be.equal('0x');
done();
});

View File

@ -17,6 +17,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
chaiSetup.configure();
const expect = chai.expect;
const DEFAULT_NUM_ACCOUNTS = 10;
describe('MnemonicWalletSubprovider', () => {
let subprovider: MnemonicWalletSubprovider;
@ -32,7 +33,7 @@ describe('MnemonicWalletSubprovider', () => {
const accounts = await subprovider.getAccountsAsync();
expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
expect(accounts[1]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_1);
expect(accounts.length).to.be.equal(10);
expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
});
it('signs a personal message', async () => {
const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
@ -89,7 +90,7 @@ describe('MnemonicWalletSubprovider', () => {
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
expect(response.result.length).to.be.equal(10);
expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
done();
});
provider.sendAsync(payload, callback);

View File

@ -13,6 +13,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
const expect = chai.expect;
chaiSetup.configure();
const DEFAULT_NUM_ACCOUNTS = 10;
describe('RedundantSubprovider', () => {
let provider: Web3ProviderEngine;
@ -31,7 +32,7 @@ describe('RedundantSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.length).to.be.equal(10);
expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
done();
});
provider.sendAsync(payload, callback);
@ -54,7 +55,7 @@ describe('RedundantSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.length).to.be.equal(10);
expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS);
done();
});
provider.sendAsync(payload, callback);

View File

@ -0,0 +1,5 @@
export const constants = {
SUCCESS_STATUS: 200,
SERVICE_UNAVAILABLE_STATUS: 503,
BAD_REQUEST_STATUS: 400,
};

View File

@ -15,6 +15,7 @@ import ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import { configs } from './configs';
import { constants } from './constants';
import { DispatchQueue } from './dispatch_queue';
import { dispenseAssetTasks } from './dispense_asset_tasks';
import { rpcUrls } from './rpc_urls';
@ -80,7 +81,7 @@ export class Handler {
};
});
const payload = JSON.stringify(queueInfo);
res.status(200).send(payload);
res.status(constants.SUCCESS_STATUS).send(payload);
}
public dispenseEther(req: express.Request, res: express.Response): void {
this._dispenseAsset(req, res, RequestedAssetType.ETH);
@ -120,11 +121,11 @@ export class Handler {
}
const didAddToQueue = networkConfig.dispatchQueue.add(dispenserTask);
if (!didAddToQueue) {
res.status(503).send('QUEUE_IS_FULL');
res.status(constants.SERVICE_UNAVAILABLE_STATUS).send('QUEUE_IS_FULL');
return;
}
logUtils.log(`Added ${recipient} to queue: ${requestedAssetType} networkId: ${networkId}`);
res.status(200).end();
res.status(constants.SUCCESS_STATUS).end();
}
private async _dispenseOrderAsync(
req: express.Request,
@ -133,7 +134,7 @@ export class Handler {
): Promise<void> {
const networkConfig = _.get(this._networkConfigByNetworkId, req.params.networkId);
if (_.isUndefined(networkConfig)) {
res.status(400).send('UNSUPPORTED_NETWORK_ID');
res.status(constants.BAD_REQUEST_STATUS).send('UNSUPPORTED_NETWORK_ID');
return;
}
const zeroEx = networkConfig.zeroEx;
@ -173,6 +174,6 @@ export class Handler {
const signedOrderHash = ZeroEx.getOrderHashHex(signedOrder);
const payload = JSON.stringify(signedOrder);
logUtils.log(`Dispensed signed order: ${payload}`);
res.status(200).send(payload);
res.status(constants.SUCCESS_STATUS).send(payload);
}
}

View File

@ -3,6 +3,7 @@ import { NextFunction, Request, Response } from 'express';
import * as _ from 'lodash';
import { configs } from './configs';
import { constants } from './constants';
import { rpcUrls } from './rpc_urls';
const DEFAULT_NETWORK_ID = 42; // kovan
@ -11,7 +12,7 @@ export const parameterTransformer = {
transform(req: Request, res: Response, next: NextFunction): void {
const recipientAddress = req.params.recipient;
if (_.isUndefined(recipientAddress) || !addressUtils.isAddress(recipientAddress)) {
res.status(400).send('INVALID_RECIPIENT_ADDRESS');
res.status(constants.BAD_REQUEST_STATUS).send('INVALID_RECIPIENT_ADDRESS');
return;
}
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
@ -19,7 +20,7 @@ export const parameterTransformer = {
const networkId = _.get(req.query, 'networkId', DEFAULT_NETWORK_ID);
const rpcUrlIfExists = _.get(rpcUrls, networkId);
if (_.isUndefined(rpcUrlIfExists)) {
res.status(400).send('UNSUPPORTED_NETWORK_ID');
res.status(constants.BAD_REQUEST_STATUS).send('UNSUPPORTED_NETWORK_ID');
return;
}
req.params.networkId = networkId;

View File

@ -1,6 +1,7 @@
import * as bodyParser from 'body-parser';
import * as express from 'express';
import { constants } from './constants';
import { errorReporter } from './error_reporter';
import { Handler } from './handler';
import { parameterTransformer } from './parameter_transformer';
@ -18,7 +19,7 @@ app.use((req, res, next) => {
const handler = new Handler();
app.get('/ping', (req: express.Request, res: express.Response) => {
res.status(200).send('pong');
res.status(constants.SUCCESS_STATUS).send('pong');
});
app.get('/info', handler.getQueueInfo.bind(handler));
app.get('/ether/:recipient', parameterTransformer.transform, handler.dispenseEther.bind(handler));
@ -28,5 +29,6 @@ app.get('/order/zrx/:recipient', parameterTransformer.transform, handler.dispens
// Log to rollbar any errors unhandled by handlers
app.use(errorReporter.errorHandler());
const port = process.env.PORT || 3000;
const DEFAULT_PORT = 3000;
const port = process.env.PORT || DEFAULT_PORT;
app.listen(port);

View File

@ -23,7 +23,8 @@ export class AbiDecoder {
formatted = formatted.slice(2);
}
formatted = _.padStart(formatted, 40, '0');
const desiredLength = 40;
formatted = _.padStart(formatted, desiredLength, '0');
return `0x${formatted}`;
}
constructor(abiArrays: AbiDefinition[][]) {
@ -45,16 +46,17 @@ export class AbiDecoder {
const dataTypes = _.map(nonIndexedInputs, input => input.type);
const decodedData = ethersInterface.events[event.name].parse(log.data);
let failedToDecode = false;
let didFailToDecode = false;
_.forEach(event.inputs, (param: EventParameter, i: number) => {
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
let value: BigNumber | string | number = param.indexed ? log.topics[topicsIndex++] : decodedData[i];
if (_.isUndefined(value)) {
failedToDecode = true;
didFailToDecode = true;
return;
}
if (param.type === SolidityTypes.Address) {
value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
const baseHex = 16;
value = AbiDecoder._padZeros(new BigNumber(value).toString(baseHex));
} else if (param.type === SolidityTypes.Uint256 || param.type === SolidityTypes.Uint) {
value = new BigNumber(value);
} else if (param.type === SolidityTypes.Uint8) {
@ -63,7 +65,7 @@ export class AbiDecoder {
decodedParams[param.name] = value;
});
if (failedToDecode) {
if (didFailToDecode) {
return log;
} else {
return {

View File

@ -9,11 +9,16 @@ export const addressUtils = {
const unprefixedAddress = address.replace('0x', '');
const addressHash = jsSHA3.keccak256(unprefixedAddress.toLowerCase());
for (let i = 0; i < 40; i++) {
const addressLength = 40;
for (let i = 0; i < addressLength; i++) {
// The nth letter should be uppercase if the nth digit of casemap is 1
const hexBase = 16;
const lowercaseRange = 7;
if (
(parseInt(addressHash[i], 16) > 7 && unprefixedAddress[i].toUpperCase() !== unprefixedAddress[i]) ||
(parseInt(addressHash[i], 16) <= 7 && unprefixedAddress[i].toLowerCase() !== unprefixedAddress[i])
(parseInt(addressHash[i], hexBase) > lowercaseRange &&
unprefixedAddress[i].toUpperCase() !== unprefixedAddress[i]) ||
(parseInt(addressHash[i], hexBase) <= lowercaseRange &&
unprefixedAddress[i].toLowerCase() !== unprefixedAddress[i])
) {
return false;
}

View File

@ -6,18 +6,18 @@ export const intervalUtils = {
intervalMs: number,
onError: (err: Error) => void,
): NodeJS.Timer {
let locked = false;
let isLocked = false;
const intervalId = setInterval(async () => {
if (locked) {
if (isLocked) {
return;
} else {
locked = true;
isLocked = true;
try {
await fn();
} catch (err) {
onError(err);
}
locked = false;
isLocked = false;
}
}, intervalMs);
return intervalId;

View File

@ -19,6 +19,8 @@ import * as Web3 from 'web3';
import { Web3WrapperErrors } from './types';
const BASE_TEN = 10;
/**
* A wrapper around the Web3.js 0.x library that provides a consistent, clean promise-based interface.
*/
@ -48,7 +50,7 @@ export class Web3Wrapper {
* @return The amount in units.
*/
public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber {
const aUnit = new BigNumber(10).pow(decimals);
const aUnit = new BigNumber(BASE_TEN).pow(decimals);
const unit = amount.div(aUnit);
return unit;
}
@ -61,7 +63,7 @@ export class Web3Wrapper {
* @return The amount in baseUnits.
*/
public static toBaseUnitAmount(amount: BigNumber, decimals: number): BigNumber {
const unit = new BigNumber(10).pow(decimals);
const unit = new BigNumber(BASE_TEN).pow(decimals);
const baseUnitAmount = amount.times(unit);
const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
if (hasDecimals) {
@ -180,8 +182,8 @@ export class Web3Wrapper {
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
const code = await promisify<string>(this._web3.eth.getCode)(address);
// Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients
const codeIsEmpty = /^0x0{0,40}$/i.test(code);
return !codeIsEmpty;
const isCodeEmpty = /^0x0{0,40}$/i.test(code);
return !isCodeEmpty;
}
/**
* Sign a message with a specific address's private key (`eth_sign`)
@ -336,16 +338,16 @@ export class Web3Wrapper {
pollingIntervalMs: number = 1000,
timeoutMs?: number,
): Promise<TransactionReceiptWithDecodedLogs> {
let timeoutExceeded = false;
let wasTimeoutExceeded = false;
if (timeoutMs) {
setTimeout(() => (timeoutExceeded = true), timeoutMs);
setTimeout(() => (wasTimeoutExceeded = true), timeoutMs);
}
const txReceiptPromise = new Promise(
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
const intervalId = intervalUtils.setAsyncExcludingInterval(
async () => {
if (timeoutExceeded) {
if (wasTimeoutExceeded) {
intervalUtils.clearAsyncExcludingInterval(intervalId);
return reject(Web3WrapperErrors.TransactionMiningTimeout);
}

View File

@ -157,14 +157,14 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
const maxLength = 30;
const tokens = _.values(this.props.tokenByAddress);
const tokenWithNameIfExists = _.find(tokens, { name });
const tokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
const doesTokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
if (name === '') {
nameErrText = 'Name is required';
} else if (!this._isValidName(name)) {
nameErrText = 'Name should only contain letters, digits and spaces';
} else if (name.length > maxLength) {
nameErrText = `Max length is ${maxLength}`;
} else if (tokenWithNameExists) {
} else if (doesTokenWithNameExists) {
nameErrText = 'Token with this name already exists';
}
@ -177,14 +177,14 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
let symbolErrText = '';
const maxLength = 5;
const tokens = _.values(this.props.tokenByAddress);
const tokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol }));
const doesTokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol }));
if (symbol === '') {
symbolErrText = 'Symbol is required';
} else if (!this._isAlphanumeric(symbol)) {
symbolErrText = 'Can only include alphanumeric characters';
} else if (symbol.length > maxLength) {
symbolErrText = `Max length is ${maxLength}`;
} else if (tokenWithSymbolExists) {
} else if (doesTokenWithSymbolExists) {
symbolErrText = 'Token with symbol already exists';
}

View File

@ -56,8 +56,8 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
this._isUnmounted = true;
}
public render(): React.ReactNode {
const readyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
if (!readyToRender) {
const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
if (!isReadyToRender) {
return (
<div className="col col-12" style={{ ...styles.root, height: '100%' }}>
<div

View File

@ -4,6 +4,7 @@
"no-implicit-dependencies": false,
"no-object-literal-type-assertion": false,
"completed-docs": false,
"prefer-function-over-method": false
"prefer-function-over-method": false,
"custom-no-magic-numbers": false
}
}