Merge pull request #594 from 0xProject/improvement/addCustomTslintRules
Add more tslint rules
This commit is contained in:
commit
cc840a6911
@ -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' },
|
||||
|
@ -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,
|
||||
|
@ -11,6 +11,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', () => {
|
||||
@ -252,3 +253,4 @@ describe('Assertions', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
|
@ -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' },
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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)) {
|
||||
|
@ -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());
|
||||
|
@ -42,7 +42,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 = {
|
||||
@ -60,7 +60,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 () => {
|
||||
@ -155,6 +154,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(
|
||||
|
@ -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,
|
||||
|
@ -106,6 +106,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,
|
||||
@ -172,6 +173,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(
|
||||
@ -206,6 +208,7 @@ describe('OrderValidation', () => {
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const nonTakerAddress = userAddresses[6];
|
||||
return expect(
|
||||
contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
@ -353,6 +356,7 @@ describe('OrderValidation', () => {
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||
expect(
|
||||
transferFromAsync
|
||||
@ -423,6 +427,7 @@ describe('OrderValidation', () => {
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||
expect(
|
||||
transferFromAsync
|
||||
@ -491,6 +496,7 @@ describe('OrderValidation', () => {
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
||||
expect(makerFillAmount).to.be.bignumber.equal(makerTokenAmount);
|
||||
@ -518,6 +524,7 @@ describe('OrderValidation', () => {
|
||||
);
|
||||
const makerPartialFee = makerFee.div(2);
|
||||
const takerPartialFee = takerFee.div(2);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||
const partialMakerFee = transferFromAsync.getCall(2).args[3];
|
||||
expect(partialMakerFee).to.be.bignumber.equal(makerPartialFee);
|
||||
|
@ -124,21 +124,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();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -100,8 +100,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, {
|
||||
|
@ -118,8 +118,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();
|
||||
|
@ -1,3 +1,6 @@
|
||||
{
|
||||
"extends": ["@0xproject/tslint-config"]
|
||||
"extends": ["@0xproject/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,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', () => {
|
||||
@ -182,6 +183,7 @@ describe('Schema', () => {
|
||||
validateAgainstSchema(testCases, tokenSchema);
|
||||
});
|
||||
it('should fail for invalid token', () => {
|
||||
const num = 4;
|
||||
const testCases = [
|
||||
{
|
||||
...token,
|
||||
@ -192,7 +194,7 @@ describe('Schema', () => {
|
||||
decimals: undefined,
|
||||
},
|
||||
[],
|
||||
4,
|
||||
num,
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, tokenSchema, shouldFail);
|
||||
@ -871,10 +873,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);
|
||||
@ -882,13 +886,14 @@ describe('Schema', () => {
|
||||
});
|
||||
describe('#txDataSchema', () => {
|
||||
it('should validate valid txData', () => {
|
||||
const bigNumGasAmount = new BigNumber(42);
|
||||
const testCases = [
|
||||
{
|
||||
from: NULL_ADDRESS,
|
||||
},
|
||||
{
|
||||
from: NULL_ADDRESS,
|
||||
gas: new BigNumber(42),
|
||||
gas: bigNumGasAmount,
|
||||
},
|
||||
{
|
||||
from: NULL_ADDRESS,
|
||||
|
@ -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,
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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),
|
||||
|
@ -47,12 +47,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();
|
||||
});
|
||||
@ -67,7 +68,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();
|
||||
});
|
||||
});
|
||||
@ -111,10 +113,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] });
|
||||
|
@ -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);
|
||||
}
|
||||
/**
|
||||
|
@ -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());
|
||||
|
@ -22,6 +22,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;
|
||||
@ -84,13 +85,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) => {
|
||||
@ -106,13 +107,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);
|
||||
});
|
||||
@ -140,8 +141,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)(
|
||||
@ -154,7 +161,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) => {
|
||||
@ -181,8 +188,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)(
|
||||
@ -195,7 +208,7 @@ describe('ExpirationWatcher', () => {
|
||||
},
|
||||
);
|
||||
expirationWatcher.subscribe(callbackAsync);
|
||||
timer.tick(order2Lifetime * 1000);
|
||||
timer.tick(order2Lifetime * MILISECONDS_IN_SECOND);
|
||||
})().catch(done);
|
||||
});
|
||||
});
|
||||
|
@ -9,7 +9,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,
|
||||
|
@ -269,8 +269,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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -39,8 +39,13 @@ 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 metadataByteLength = 43;
|
||||
const metadataHexLength = metadataByteLength * 2;
|
||||
const unlinkedBinaryWithoutMetadata = exchangeArtifact.compilerOutput.evm.bytecode.object.slice(
|
||||
2,
|
||||
-metadataHexLength,
|
||||
);
|
||||
const exchangeBinaryWithoutMetadata = exchange_binary.slice(0, -metadataHexLength);
|
||||
expect(unlinkedBinaryWithoutMetadata).to.equal(exchangeBinaryWithoutMetadata);
|
||||
});
|
||||
});
|
||||
|
@ -40,12 +40,14 @@ describe('Collect coverage entries', () => {
|
||||
const coverageEntries = collectCoverageEntries(simpleStorageContract);
|
||||
const fnIds = _.keys(coverageEntries.fnMap);
|
||||
expect(coverageEntries.fnMap[fnIds[0]].name).to.be.equal('set');
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
expect(coverageEntries.fnMap[fnIds[0]].line).to.be.equal(5);
|
||||
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');
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
expect(coverageEntries.fnMap[fnIds[1]].line).to.be.equal(8);
|
||||
const getFunction = `function get() constant returns (uint retVal) {
|
||||
return storedData;
|
||||
@ -122,6 +124,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']);
|
||||
|
@ -12,6 +12,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 };
|
||||
|
@ -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
|
||||
|
@ -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');
|
||||
|
@ -24,6 +24,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,
|
||||
@ -46,7 +47,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,
|
||||
@ -61,7 +62,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,
|
||||
@ -76,7 +77,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,
|
||||
@ -100,7 +101,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');
|
||||
@ -108,7 +109,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');
|
||||
|
@ -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}`;
|
||||
}
|
||||
|
@ -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}`;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
@ -20,6 +20,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();
|
||||
@ -41,7 +43,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();
|
||||
@ -105,7 +107,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);
|
||||
@ -123,7 +125,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();
|
||||
});
|
||||
@ -143,7 +145,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();
|
||||
});
|
||||
@ -197,7 +199,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();
|
||||
});
|
||||
|
@ -21,6 +21,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;
|
||||
@ -73,7 +74,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;
|
||||
@ -119,7 +120,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();
|
||||
});
|
||||
@ -176,7 +177,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();
|
||||
});
|
||||
|
@ -18,6 +18,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const DEFAULT_NUM_ACCOUNTS = 10;
|
||||
|
||||
describe('MnemonicWalletSubprovider', () => {
|
||||
let subprovider: MnemonicWalletSubprovider;
|
||||
@ -33,7 +34,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));
|
||||
@ -90,7 +91,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);
|
||||
|
@ -14,6 +14,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
|
||||
|
||||
const expect = chai.expect;
|
||||
chaiSetup.configure();
|
||||
const DEFAULT_NUM_ACCOUNTS = 10;
|
||||
|
||||
describe('RedundantSubprovider', () => {
|
||||
let provider: Web3ProviderEngine;
|
||||
@ -32,7 +33,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);
|
||||
@ -55,7 +56,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);
|
||||
|
5
packages/testnet-faucets/src/ts/constants.ts
Normal file
5
packages/testnet-faucets/src/ts/constants.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const constants = {
|
||||
SUCCESS_STATUS: 200,
|
||||
SERVICE_UNAVAILABLE_STATUS: 503,
|
||||
BAD_REQUEST_STATUS: 400,
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -45,7 +45,8 @@
|
||||
"lodash": "^4.17.4",
|
||||
"tslint": "5.8.0",
|
||||
"tslint-eslint-rules": "^4.1.1",
|
||||
"tslint-react": "^3.2.0"
|
||||
"tslint-react": "^3.2.0",
|
||||
"tsutils": "^2.12.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
68
packages/tslint-config/rules/booleanNamingRule.ts
Normal file
68
packages/tslint-config/rules/booleanNamingRule.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as Lint from 'tslint';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const VALID_BOOLEAN_PREFIXES = ['is', 'does', 'should', 'was', 'has', 'can', 'did', 'would'];
|
||||
|
||||
export class Rule extends Lint.Rules.TypedRule {
|
||||
public static FAILURE_STRING = `Boolean variable names should begin with: ${VALID_BOOLEAN_PREFIXES.join(', ')}`;
|
||||
|
||||
public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
|
||||
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
|
||||
}
|
||||
}
|
||||
|
||||
function walk(ctx: Lint.WalkContext<void>, tc: ts.TypeChecker): void {
|
||||
traverse(ctx.sourceFile);
|
||||
|
||||
function traverse(node: ts.Node): void {
|
||||
checkNodeForViolations(ctx, node, tc);
|
||||
return ts.forEachChild(node, traverse);
|
||||
}
|
||||
}
|
||||
|
||||
function checkNodeForViolations(ctx: Lint.WalkContext<void>, node: ts.Node, tc: ts.TypeChecker): void {
|
||||
switch (node.kind) {
|
||||
// Handle: const { timestamp } = ...
|
||||
case ts.SyntaxKind.BindingElement: {
|
||||
const bindingElementNode = node as ts.BindingElement;
|
||||
if (bindingElementNode.name.kind === ts.SyntaxKind.Identifier) {
|
||||
handleBooleanNaming(bindingElementNode, tc, ctx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle regular assignments: const block = ...
|
||||
case ts.SyntaxKind.VariableDeclaration:
|
||||
const variableDeclarationNode = node as ts.VariableDeclaration;
|
||||
if (variableDeclarationNode.name.kind === ts.SyntaxKind.Identifier) {
|
||||
handleBooleanNaming(node as ts.VariableDeclaration, tc, ctx);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
_.noop();
|
||||
}
|
||||
}
|
||||
|
||||
function handleBooleanNaming(
|
||||
node: ts.VariableDeclaration | ts.BindingElement,
|
||||
tc: ts.TypeChecker,
|
||||
ctx: Lint.WalkContext<void>,
|
||||
): void {
|
||||
const nodeName = node.name;
|
||||
const variableName = nodeName.getText();
|
||||
const lowercasedName = _.toLower(variableName);
|
||||
const typeNode = tc.getTypeAtLocation(node);
|
||||
const typeName = (typeNode as any).intrinsicName;
|
||||
if (typeName === 'boolean') {
|
||||
const hasProperName = !_.isUndefined(
|
||||
_.find(VALID_BOOLEAN_PREFIXES, prefix => {
|
||||
return _.startsWith(lowercasedName, prefix);
|
||||
}),
|
||||
);
|
||||
if (!hasProperName) {
|
||||
ctx.addFailureAtNode(node, Rule.FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
}
|
76
packages/tslint-config/rules/customNoMagicNumbersRule.ts
Normal file
76
packages/tslint-config/rules/customNoMagicNumbersRule.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import * as Lint from 'tslint';
|
||||
import { isPrefixUnaryExpression } from 'tsutils';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
/**
|
||||
* A modified version of the no-magic-numbers rule that allows for magic numbers
|
||||
* when instantiating a BigNumber instance.
|
||||
* E.g We want to be able to write:
|
||||
* const amount = new BigNumber(5);
|
||||
* Original source: https://github.com/palantir/tslint/blob/42b058a6baa688f8be8558b277eb056c3ff79818/src/rules/noMagicNumbersRule.ts
|
||||
*/
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static ALLOWED_NODES = new Set<ts.SyntaxKind>([
|
||||
ts.SyntaxKind.ExportAssignment,
|
||||
ts.SyntaxKind.FirstAssignment,
|
||||
ts.SyntaxKind.LastAssignment,
|
||||
ts.SyntaxKind.PropertyAssignment,
|
||||
ts.SyntaxKind.ShorthandPropertyAssignment,
|
||||
ts.SyntaxKind.VariableDeclaration,
|
||||
ts.SyntaxKind.VariableDeclarationList,
|
||||
ts.SyntaxKind.EnumMember,
|
||||
ts.SyntaxKind.PropertyDeclaration,
|
||||
ts.SyntaxKind.Parameter,
|
||||
]);
|
||||
|
||||
public static DEFAULT_ALLOWED = [-1, 0, 1];
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
const allowedNumbers = this.ruleArguments.length > 0 ? this.ruleArguments : Rule.DEFAULT_ALLOWED;
|
||||
return this.applyWithWalker(
|
||||
new CustomNoMagicNumbersWalker(sourceFile, this.ruleName, new Set(allowedNumbers.map(String))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:max-classes-per-file
|
||||
class CustomNoMagicNumbersWalker extends Lint.AbstractWalker<Set<string>> {
|
||||
public static FAILURE_STRING = "'magic numbers' are not allowed";
|
||||
private static _isNegativeNumberLiteral(
|
||||
node: ts.Node,
|
||||
): node is ts.PrefixUnaryExpression & { operand: ts.NumericLiteral } {
|
||||
return (
|
||||
isPrefixUnaryExpression(node) &&
|
||||
node.operator === ts.SyntaxKind.MinusToken &&
|
||||
node.operand.kind === ts.SyntaxKind.NumericLiteral
|
||||
);
|
||||
}
|
||||
public walk(sourceFile: ts.SourceFile): void {
|
||||
const cb = (node: ts.Node): void => {
|
||||
if (node.kind === ts.SyntaxKind.NumericLiteral) {
|
||||
return this.checkNumericLiteral(node, (node as ts.NumericLiteral).text);
|
||||
}
|
||||
if (CustomNoMagicNumbersWalker._isNegativeNumberLiteral(node)) {
|
||||
return this.checkNumericLiteral(node, `-${(node.operand as ts.NumericLiteral).text}`);
|
||||
}
|
||||
return ts.forEachChild(node, cb);
|
||||
};
|
||||
return ts.forEachChild(sourceFile, cb);
|
||||
}
|
||||
|
||||
// tslint:disable:no-non-null-assertion
|
||||
// tslint:disable-next-line:underscore-private-and-protected
|
||||
private checkNumericLiteral(node: ts.Node, num: string): void {
|
||||
if (!Rule.ALLOWED_NODES.has(node.parent!.kind) && !this.options.has(num)) {
|
||||
if (node.parent!.kind === ts.SyntaxKind.NewExpression) {
|
||||
const className = (node.parent! as any).expression.escapedText;
|
||||
const BIG_NUMBER_NEW_EXPRESSION = 'BigNumber';
|
||||
if (className === BIG_NUMBER_NEW_EXPRESSION) {
|
||||
return; // noop
|
||||
}
|
||||
}
|
||||
this.addFailureAtNode(node, CustomNoMagicNumbersWalker.FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
// tslint:enable:no-non-null-assertion
|
||||
}
|
@ -5,7 +5,10 @@
|
||||
"arrow-parens": [true, "ban-single-arg-parens"],
|
||||
"arrow-return-shorthand": true,
|
||||
"async-suffix": true,
|
||||
"boolean-naming": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"await-promise": true,
|
||||
"custom-no-magic-numbers": [true, 0, 1, 2, 3, -1],
|
||||
"binary-expression-operand-order": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
|
@ -23,7 +23,8 @@ export class AbiDecoder {
|
||||
formatted = formatted.slice(2);
|
||||
}
|
||||
|
||||
formatted = _.padStart(formatted, 40, '0');
|
||||
const addressLength = 40;
|
||||
formatted = _.padStart(formatted, addressLength, '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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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';
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user