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 = {
|
export const zeroExPublicNetworkConfigSchema = {
|
||||||
id: '/ZeroExPublicNetworkConfig',
|
id: '/ZeroExPublicNetworkConfig',
|
||||||
properties: {
|
properties: {
|
||||||
networkId: {
|
networkId: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
enum: [1, 3, 4, 42, 50],
|
enum: [
|
||||||
|
networkNameToId.mainnet,
|
||||||
|
networkNameToId.ropsten,
|
||||||
|
networkNameToId.rinkeby,
|
||||||
|
networkNameToId.kovan,
|
||||||
|
networkNameToId.ganache,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
gasPrice: { $ref: '/Number' },
|
gasPrice: { $ref: '/Number' },
|
||||||
zrxContractAddress: { $ref: '/Address' },
|
zrxContractAddress: { $ref: '/Address' },
|
||||||
|
@ -8,7 +8,8 @@ import { provider } from './utils/web3_wrapper';
|
|||||||
before('migrate contracts', async function(): Promise<void> {
|
before('migrate contracts', async function(): Promise<void> {
|
||||||
// HACK: Since the migrations take longer then our global mocha timeout limit
|
// HACK: Since the migrations take longer then our global mocha timeout limit
|
||||||
// we manually increase it for this before hook.
|
// we manually increase it for this before hook.
|
||||||
this.timeout(20000);
|
const mochaTestTimeoutMs = 20000;
|
||||||
|
this.timeout(mochaTestTimeoutMs);
|
||||||
const txDefaults = {
|
const txDefaults = {
|
||||||
gas: devConstants.GAS_ESTIMATE,
|
gas: devConstants.GAS_ESTIMATE,
|
||||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||||
|
@ -11,6 +11,7 @@ chai.config.includeStack = true;
|
|||||||
chai.use(dirtyChai);
|
chai.use(dirtyChai);
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
// tslint:disable:custom-no-magic-numbers
|
||||||
describe('Assertions', () => {
|
describe('Assertions', () => {
|
||||||
const variableName = 'variable';
|
const variableName = 'variable';
|
||||||
describe('#isBigNumber', () => {
|
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 = {
|
export const contractWrappersPublicNetworkConfigSchema = {
|
||||||
id: '/ZeroExContractPublicNetworkConfig',
|
id: '/ZeroExContractPublicNetworkConfig',
|
||||||
properties: {
|
properties: {
|
||||||
networkId: {
|
networkId: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
enum: [1, 3, 4, 42, 50],
|
enum: [
|
||||||
|
networkNameToId.mainnet,
|
||||||
|
networkNameToId.kovan,
|
||||||
|
networkNameToId.ropsten,
|
||||||
|
networkNameToId.rinkeby,
|
||||||
|
networkNameToId.ganache,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
gasPrice: { $ref: '/Number' },
|
gasPrice: { $ref: '/Number' },
|
||||||
zrxContractAddress: { $ref: '/Address' },
|
zrxContractAddress: { $ref: '/Address' },
|
||||||
|
@ -6,6 +6,7 @@ export const constants = {
|
|||||||
INVALID_JUMP_PATTERN: 'invalid JUMP at',
|
INVALID_JUMP_PATTERN: 'invalid JUMP at',
|
||||||
OUT_OF_GAS_PATTERN: 'out of gas',
|
OUT_OF_GAS_PATTERN: 'out of gas',
|
||||||
INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string',
|
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),
|
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
|
||||||
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
|
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
|
||||||
};
|
};
|
||||||
|
@ -73,14 +73,14 @@ export const filterUtils = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!_.isUndefined(filter.topics)) {
|
if (!_.isUndefined(filter.topics)) {
|
||||||
return filterUtils.matchesTopics(log.topics, filter.topics);
|
return filterUtils.doesMatchTopics(log.topics, filter.topics);
|
||||||
}
|
}
|
||||||
return true;
|
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 matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
|
||||||
const matchesTopics = _.every(matchesTopic);
|
const doesMatchTopics = _.every(matchesTopic);
|
||||||
return matchesTopics;
|
return doesMatchTopics;
|
||||||
},
|
},
|
||||||
matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean {
|
matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean {
|
||||||
if (_.isArray(filterTopic)) {
|
if (_.isArray(filterTopic)) {
|
||||||
|
@ -5,7 +5,8 @@ export const utils = {
|
|||||||
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
||||||
},
|
},
|
||||||
getCurrentUnixTimestampSec(): BigNumber {
|
getCurrentUnixTimestampSec(): BigNumber {
|
||||||
return new BigNumber(Date.now() / 1000).round();
|
const milisecondsInSecond = 1000;
|
||||||
|
return new BigNumber(Date.now() / milisecondsInSecond).round();
|
||||||
},
|
},
|
||||||
getCurrentUnixTimestampMs(): BigNumber {
|
getCurrentUnixTimestampMs(): BigNumber {
|
||||||
return new BigNumber(Date.now());
|
return new BigNumber(Date.now());
|
||||||
|
@ -42,7 +42,7 @@ describe('EtherTokenWrapper', () => {
|
|||||||
let addressWithETH: string;
|
let addressWithETH: string;
|
||||||
let wethContractAddress: string;
|
let wethContractAddress: string;
|
||||||
let depositWeiAmount: BigNumber;
|
let depositWeiAmount: BigNumber;
|
||||||
let decimalPlaces: number;
|
const decimalPlaces = 7;
|
||||||
let addressWithoutFunds: string;
|
let addressWithoutFunds: string;
|
||||||
const gasPrice = new BigNumber(1);
|
const gasPrice = new BigNumber(1);
|
||||||
const zeroExConfig = {
|
const zeroExConfig = {
|
||||||
@ -60,7 +60,6 @@ describe('EtherTokenWrapper', () => {
|
|||||||
addressWithETH = userAddresses[0];
|
addressWithETH = userAddresses[0];
|
||||||
wethContractAddress = contractWrappers.etherToken.getContractAddressIfExists() as string;
|
wethContractAddress = contractWrappers.etherToken.getContractAddressIfExists() as string;
|
||||||
depositWeiAmount = Web3Wrapper.toWei(new BigNumber(5));
|
depositWeiAmount = Web3Wrapper.toWei(new BigNumber(5));
|
||||||
decimalPlaces = 7;
|
|
||||||
addressWithoutFunds = userAddresses[1];
|
addressWithoutFunds = userAddresses[1];
|
||||||
});
|
});
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@ -155,6 +154,7 @@ describe('EtherTokenWrapper', () => {
|
|||||||
const preWETHBalance = await contractWrappers.token.getBalanceAsync(wethContractAddress, addressWithETH);
|
const preWETHBalance = await contractWrappers.token.getBalanceAsync(wethContractAddress, addressWithETH);
|
||||||
expect(preWETHBalance).to.be.bignumber.equal(0);
|
expect(preWETHBalance).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const overWETHBalance = preWETHBalance.add(999999999);
|
const overWETHBalance = preWETHBalance.add(999999999);
|
||||||
|
|
||||||
return expect(
|
return expect(
|
||||||
|
@ -8,7 +8,8 @@ import { provider } from './utils/web3_wrapper';
|
|||||||
before('migrate contracts', async function(): Promise<void> {
|
before('migrate contracts', async function(): Promise<void> {
|
||||||
// HACK: Since the migrations take longer then our global mocha timeout limit
|
// HACK: Since the migrations take longer then our global mocha timeout limit
|
||||||
// we manually increase it for this before hook.
|
// we manually increase it for this before hook.
|
||||||
this.timeout(20000);
|
const mochaTestTimeoutMs = 20000;
|
||||||
|
this.timeout(mochaTestTimeoutMs);
|
||||||
const txDefaults = {
|
const txDefaults = {
|
||||||
gas: devConstants.GAS_ESTIMATE,
|
gas: devConstants.GAS_ESTIMATE,
|
||||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||||
|
@ -106,6 +106,7 @@ describe('OrderValidation', () => {
|
|||||||
});
|
});
|
||||||
it('should succeed if the order is asymmetric and fillable', async () => {
|
it('should succeed if the order is asymmetric and fillable', async () => {
|
||||||
const makerFillableAmount = fillableAmount;
|
const makerFillableAmount = fillableAmount;
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const takerFillableAmount = fillableAmount.minus(4);
|
const takerFillableAmount = fillableAmount.minus(4);
|
||||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress,
|
makerTokenAddress,
|
||||||
@ -172,6 +173,7 @@ describe('OrderValidation', () => {
|
|||||||
fillableAmount,
|
fillableAmount,
|
||||||
);
|
);
|
||||||
// 27 <--> 28
|
// 27 <--> 28
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
|
signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
|
||||||
return expect(
|
return expect(
|
||||||
contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync(
|
contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||||
@ -206,6 +208,7 @@ describe('OrderValidation', () => {
|
|||||||
takerAddress,
|
takerAddress,
|
||||||
fillableAmount,
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const nonTakerAddress = userAddresses[6];
|
const nonTakerAddress = userAddresses[6];
|
||||||
return expect(
|
return expect(
|
||||||
contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync(
|
contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||||
@ -353,6 +356,7 @@ describe('OrderValidation', () => {
|
|||||||
takerAddress,
|
takerAddress,
|
||||||
zrxTokenAddress,
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync
|
transferFromAsync
|
||||||
@ -423,6 +427,7 @@ describe('OrderValidation', () => {
|
|||||||
takerAddress,
|
takerAddress,
|
||||||
zrxTokenAddress,
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync
|
transferFromAsync
|
||||||
@ -491,6 +496,7 @@ describe('OrderValidation', () => {
|
|||||||
takerAddress,
|
takerAddress,
|
||||||
zrxTokenAddress,
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
||||||
expect(makerFillAmount).to.be.bignumber.equal(makerTokenAmount);
|
expect(makerFillAmount).to.be.bignumber.equal(makerTokenAmount);
|
||||||
@ -518,6 +524,7 @@ describe('OrderValidation', () => {
|
|||||||
);
|
);
|
||||||
const makerPartialFee = makerFee.div(2);
|
const makerPartialFee = makerFee.div(2);
|
||||||
const takerPartialFee = takerFee.div(2);
|
const takerPartialFee = takerFee.div(2);
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
const partialMakerFee = transferFromAsync.getCall(2).args[3];
|
const partialMakerFee = transferFromAsync.getCall(2).args[3];
|
||||||
expect(partialMakerFee).to.be.bignumber.equal(makerPartialFee);
|
expect(partialMakerFee).to.be.bignumber.equal(makerPartialFee);
|
||||||
|
@ -124,21 +124,21 @@ describe('Exchange', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return true with a valid signature', async () => {
|
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 orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, signedOrder.ecSignature, signedOrder.maker);
|
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, signedOrder.ecSignature, signedOrder.maker);
|
||||||
expect(isValidSignature).to.be.true();
|
expect(isValidSignature).to.be.true();
|
||||||
expect(success).to.be.true();
|
expect(isValidSignatureForContract).to.be.true();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false with an invalid signature', async () => {
|
it('should return false with an invalid signature', async () => {
|
||||||
signedOrder.ecSignature.r = ethUtil.bufferToHex(ethUtil.sha3('invalidR'));
|
signedOrder.ecSignature.r = ethUtil.bufferToHex(ethUtil.sha3('invalidR'));
|
||||||
signedOrder.ecSignature.s = ethUtil.bufferToHex(ethUtil.sha3('invalidS'));
|
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 orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, signedOrder.ecSignature, signedOrder.maker);
|
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, signedOrder.ecSignature, signedOrder.maker);
|
||||||
expect(isValidSignature).to.be.false();
|
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 amountToTransfer = ownerBalance;
|
||||||
|
|
||||||
const spenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender);
|
const spenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender);
|
||||||
const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
|
const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
|
||||||
expect(spenderAllowanceIsInsufficient).to.be.true();
|
expect(isSpenderAllowanceInsufficient).to.be.true();
|
||||||
|
|
||||||
return expect(
|
return expect(
|
||||||
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
|
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
|
||||||
|
@ -118,8 +118,8 @@ describe('ZRXToken', () => {
|
|||||||
const amountToTransfer = ownerBalance;
|
const amountToTransfer = ownerBalance;
|
||||||
|
|
||||||
const spenderAllowance = await zeroEx.token.getAllowanceAsync(zrxAddress, owner, spender);
|
const spenderAllowance = await zeroEx.token.getAllowanceAsync(zrxAddress, owner, spender);
|
||||||
const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
|
const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
|
||||||
expect(spenderAllowanceIsInsufficient).to.be.true();
|
expect(isSpenderAllowanceInsufficient).to.be.true();
|
||||||
|
|
||||||
const didReturnTrue = await zrx.transferFrom.callAsync(owner, spender, amountToTransfer, { from: spender });
|
const didReturnTrue = await zrx.transferFrom.callAsync(owner, spender, amountToTransfer, { from: spender });
|
||||||
expect(didReturnTrue).to.be.false();
|
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', () => {
|
describe('#blockParamSchema', () => {
|
||||||
it('should validate valid block param', () => {
|
it('should validate valid block param', () => {
|
||||||
const testCases = [42, 'latest', 'pending', 'earliest'];
|
const blockNumber = 42;
|
||||||
|
const testCases = [blockNumber, 'latest', 'pending', 'earliest'];
|
||||||
validateAgainstSchema(testCases, blockParamSchema);
|
validateAgainstSchema(testCases, blockParamSchema);
|
||||||
});
|
});
|
||||||
it('should fail for invalid block param', () => {
|
it('should fail for invalid block param', () => {
|
||||||
@ -182,6 +183,7 @@ describe('Schema', () => {
|
|||||||
validateAgainstSchema(testCases, tokenSchema);
|
validateAgainstSchema(testCases, tokenSchema);
|
||||||
});
|
});
|
||||||
it('should fail for invalid token', () => {
|
it('should fail for invalid token', () => {
|
||||||
|
const num = 4;
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
...token,
|
...token,
|
||||||
@ -192,7 +194,7 @@ describe('Schema', () => {
|
|||||||
decimals: undefined,
|
decimals: undefined,
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
4,
|
num,
|
||||||
];
|
];
|
||||||
const shouldFail = true;
|
const shouldFail = true;
|
||||||
validateAgainstSchema(testCases, tokenSchema, shouldFail);
|
validateAgainstSchema(testCases, tokenSchema, shouldFail);
|
||||||
@ -871,10 +873,12 @@ describe('Schema', () => {
|
|||||||
});
|
});
|
||||||
describe('#jsNumberSchema', () => {
|
describe('#jsNumberSchema', () => {
|
||||||
it('should validate valid js number', () => {
|
it('should validate valid js number', () => {
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const testCases = [1, 42];
|
const testCases = [1, 42];
|
||||||
validateAgainstSchema(testCases, jsNumber);
|
validateAgainstSchema(testCases, jsNumber);
|
||||||
});
|
});
|
||||||
it('should fail for invalid js number', () => {
|
it('should fail for invalid js number', () => {
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const testCases = [NaN, -1, new BigNumber(1)];
|
const testCases = [NaN, -1, new BigNumber(1)];
|
||||||
const shouldFail = true;
|
const shouldFail = true;
|
||||||
validateAgainstSchema(testCases, jsNumber, shouldFail);
|
validateAgainstSchema(testCases, jsNumber, shouldFail);
|
||||||
@ -882,13 +886,14 @@ describe('Schema', () => {
|
|||||||
});
|
});
|
||||||
describe('#txDataSchema', () => {
|
describe('#txDataSchema', () => {
|
||||||
it('should validate valid txData', () => {
|
it('should validate valid txData', () => {
|
||||||
|
const bigNumGasAmount = new BigNumber(42);
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
from: NULL_ADDRESS,
|
from: NULL_ADDRESS,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: NULL_ADDRESS,
|
from: NULL_ADDRESS,
|
||||||
gas: new BigNumber(42),
|
gas: bigNumGasAmount,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: NULL_ADDRESS,
|
from: NULL_ADDRESS,
|
||||||
|
@ -80,11 +80,12 @@ export const runMigrationsAsync = async (provider: Provider, artifactsDir: strin
|
|||||||
tokenInfo[0].swarmHash,
|
tokenInfo[0].swarmHash,
|
||||||
{ from: owner },
|
{ from: owner },
|
||||||
);
|
);
|
||||||
|
const decimals = 18;
|
||||||
await tokenReg.addToken.sendTransactionAsync(
|
await tokenReg.addToken.sendTransactionAsync(
|
||||||
zrxToken.address,
|
zrxToken.address,
|
||||||
'0x Protocol Token',
|
'0x Protocol Token',
|
||||||
'ZRX',
|
'ZRX',
|
||||||
18,
|
decimals,
|
||||||
NULL_BYTES,
|
NULL_BYTES,
|
||||||
NULL_BYTES,
|
NULL_BYTES,
|
||||||
{
|
{
|
||||||
@ -96,7 +97,7 @@ export const runMigrationsAsync = async (provider: Provider, artifactsDir: strin
|
|||||||
etherToken.address,
|
etherToken.address,
|
||||||
'Ether Token',
|
'Ether Token',
|
||||||
'WETH',
|
'WETH',
|
||||||
18,
|
decimals,
|
||||||
NULL_BYTES,
|
NULL_BYTES,
|
||||||
NULL_BYTES,
|
NULL_BYTES,
|
||||||
{
|
{
|
||||||
|
@ -158,6 +158,7 @@ export const postpublishUtils = {
|
|||||||
// HACK: tsconfig.json needs wildcard directory endings as `/**/*`
|
// HACK: tsconfig.json needs wildcard directory endings as `/**/*`
|
||||||
// but TypeDoc needs it as `/**` in order to pick up files at the root
|
// but TypeDoc needs it as `/**` in order to pick up files at the root
|
||||||
if (_.endsWith(includePath, '/**/*')) {
|
if (_.endsWith(includePath, '/**/*')) {
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
includePath = includePath.slice(0, -2);
|
includePath = includePath.slice(0, -2);
|
||||||
}
|
}
|
||||||
return includePath;
|
return includePath;
|
||||||
|
@ -285,8 +285,8 @@ function shouldAddNewChangelogEntry(currentVersion: string, changelogs: Changelo
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const lastEntry = changelogs[0];
|
const lastEntry = changelogs[0];
|
||||||
const lastEntryCurrentVersion = lastEntry.version === currentVersion;
|
const isLastEntryCurrentVersion = lastEntry.version === currentVersion;
|
||||||
return lastEntryCurrentVersion;
|
return isLastEntryCurrentVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateChangelogMd(changelogs: Changelog[]): string {
|
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.
|
* We do not use BN anywhere else in the codebase.
|
||||||
*/
|
*/
|
||||||
function bigNumberToBN(value: BigNumber): BN {
|
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)
|
// 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,
|
// 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.
|
// 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 validVParamValues = [27, 28];
|
||||||
const ecSignatureVRS = parseSignatureHexAsVRS(signature);
|
const ecSignatureVRS = parseSignatureHexAsVRS(signature);
|
||||||
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
|
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
|
||||||
@ -95,11 +96,19 @@ export async function signOrderHashAsync(
|
|||||||
function parseSignatureHexAsVRS(signatureHex: string): ECSignature {
|
function parseSignatureHexAsVRS(signatureHex: string): ECSignature {
|
||||||
const signatureBuffer = ethUtil.toBuffer(signatureHex);
|
const signatureBuffer = ethUtil.toBuffer(signatureHex);
|
||||||
let v = signatureBuffer[0];
|
let v = signatureBuffer[0];
|
||||||
if (v < 27) {
|
// HACK: Sometimes v is returned as [0, 1] and sometimes as [27, 28]
|
||||||
v += 27;
|
// 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);
|
// signatureBuffer contains vrs
|
||||||
const s = signatureBuffer.slice(33, 65);
|
const vEndIndex = 1;
|
||||||
|
const rsIndex = 33;
|
||||||
|
const r = signatureBuffer.slice(vEndIndex, rsIndex);
|
||||||
|
const sEndIndex = 65;
|
||||||
|
const s = signatureBuffer.slice(rsIndex, sEndIndex);
|
||||||
const ecSignature: ECSignature = {
|
const ecSignature: ECSignature = {
|
||||||
v,
|
v,
|
||||||
r: ethUtil.bufferToHex(r),
|
r: ethUtil.bufferToHex(r),
|
||||||
|
@ -47,12 +47,13 @@ describe('Signature utils', () => {
|
|||||||
});
|
});
|
||||||
describe('#generateSalt', () => {
|
describe('#generateSalt', () => {
|
||||||
it('generates different salts', () => {
|
it('generates different salts', () => {
|
||||||
const equal = generatePseudoRandomSalt().eq(generatePseudoRandomSalt());
|
const isEqual = generatePseudoRandomSalt().eq(generatePseudoRandomSalt());
|
||||||
expect(equal).to.be.false();
|
expect(isEqual).to.be.false();
|
||||||
});
|
});
|
||||||
it('generates salt in range [0..2^256)', () => {
|
it('generates salt in range [0..2^256)', () => {
|
||||||
const salt = generatePseudoRandomSalt();
|
const salt = generatePseudoRandomSalt();
|
||||||
expect(salt.greaterThanOrEqualTo(0)).to.be.true();
|
expect(salt.greaterThanOrEqualTo(0)).to.be.true();
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const twoPow256 = new BigNumber(2).pow(256);
|
const twoPow256 = new BigNumber(2).pow(256);
|
||||||
expect(salt.lessThan(twoPow256)).to.be.true();
|
expect(salt.lessThan(twoPow256)).to.be.true();
|
||||||
});
|
});
|
||||||
@ -67,7 +68,8 @@ describe('Signature utils', () => {
|
|||||||
expect(isValid).to.be.false();
|
expect(isValid).to.be.false();
|
||||||
});
|
});
|
||||||
it('returns true if order hash is correct', () => {
|
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();
|
expect(isValid).to.be.true();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -111,10 +113,12 @@ describe('Signature utils', () => {
|
|||||||
if (payload.method === 'eth_sign') {
|
if (payload.method === 'eth_sign') {
|
||||||
const [address, message] = payload.params;
|
const [address, message] = payload.params;
|
||||||
const signature = await web3Wrapper.signMessageAsync(address, message);
|
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, {
|
callback(null, {
|
||||||
id: 42,
|
id: 42,
|
||||||
jsonrpc: '2.0',
|
jsonrpc: '2.0',
|
||||||
result: `0x${signature.substr(130)}${signature.substr(2, 128)}`,
|
result: rsvHex,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] });
|
callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] });
|
||||||
|
@ -60,6 +60,7 @@ interface OrderStateByOrderHash {
|
|||||||
[orderHash: string]: OrderState;
|
[orderHash: string]: OrderState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const DEFAULT_CLEANUP_JOB_INTERVAL_MS = 1000 * 60 * 60; // 1h
|
const DEFAULT_CLEANUP_JOB_INTERVAL_MS = 1000 * 60 * 60; // 1h
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,7 +131,8 @@ export class OrderWatcher {
|
|||||||
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
||||||
this._orderByOrderHash[orderHash] = signedOrder;
|
this._orderByOrderHash[orderHash] = signedOrder;
|
||||||
this._addToDependentOrderHashes(signedOrder, orderHash);
|
this._addToDependentOrderHashes(signedOrder, orderHash);
|
||||||
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
|
const milisecondsInASecond = 1000;
|
||||||
|
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(milisecondsInASecond);
|
||||||
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,8 @@ export const utils = {
|
|||||||
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
||||||
},
|
},
|
||||||
getCurrentUnixTimestampSec(): BigNumber {
|
getCurrentUnixTimestampSec(): BigNumber {
|
||||||
return new BigNumber(Date.now() / 1000).round();
|
const milisecondsInASecond = 1000;
|
||||||
|
return new BigNumber(Date.now() / milisecondsInASecond).round();
|
||||||
},
|
},
|
||||||
getCurrentUnixTimestampMs(): BigNumber {
|
getCurrentUnixTimestampMs(): BigNumber {
|
||||||
return new BigNumber(Date.now());
|
return new BigNumber(Date.now());
|
||||||
|
@ -22,6 +22,7 @@ import { provider, web3Wrapper } from './utils/web3_wrapper';
|
|||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
const MILISECONDS_IN_SECOND = 1000;
|
||||||
|
|
||||||
describe('ExpirationWatcher', () => {
|
describe('ExpirationWatcher', () => {
|
||||||
let contractWrappers: ContractWrappers;
|
let contractWrappers: ContractWrappers;
|
||||||
@ -84,13 +85,13 @@ describe('ExpirationWatcher', () => {
|
|||||||
expirationUnixTimestampSec,
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash = getOrderHashHex(signedOrder);
|
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) => {
|
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)((hash: string) => {
|
||||||
expect(hash).to.be.equal(orderHash);
|
expect(hash).to.be.equal(orderHash);
|
||||||
expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
|
expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
|
||||||
});
|
});
|
||||||
expirationWatcher.subscribe(callbackAsync);
|
expirationWatcher.subscribe(callbackAsync);
|
||||||
timer.tick(orderLifetimeSec * 1000);
|
timer.tick(orderLifetimeSec * MILISECONDS_IN_SECOND);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it("doesn't emit events before order expires", (done: DoneCallback) => {
|
it("doesn't emit events before order expires", (done: DoneCallback) => {
|
||||||
@ -106,13 +107,13 @@ describe('ExpirationWatcher', () => {
|
|||||||
expirationUnixTimestampSec,
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash = getOrderHashHex(signedOrder);
|
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) => {
|
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)(async (hash: string) => {
|
||||||
done(new Error('Emitted expiration went before the order actually expired'));
|
done(new Error('Emitted expiration went before the order actually expired'));
|
||||||
});
|
});
|
||||||
expirationWatcher.subscribe(callbackAsync);
|
expirationWatcher.subscribe(callbackAsync);
|
||||||
const notEnoughTime = orderLifetimeSec - 1;
|
const notEnoughTime = orderLifetimeSec - 1;
|
||||||
timer.tick(notEnoughTime * 1000);
|
timer.tick(notEnoughTime * MILISECONDS_IN_SECOND);
|
||||||
done();
|
done();
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -140,8 +141,14 @@ describe('ExpirationWatcher', () => {
|
|||||||
);
|
);
|
||||||
const orderHash1 = getOrderHashHex(signedOrder1);
|
const orderHash1 = getOrderHashHex(signedOrder1);
|
||||||
const orderHash2 = getOrderHashHex(signedOrder2);
|
const orderHash2 = getOrderHashHex(signedOrder2);
|
||||||
expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
|
expirationWatcher.addOrder(
|
||||||
expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
|
orderHash2,
|
||||||
|
signedOrder2.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND),
|
||||||
|
);
|
||||||
|
expirationWatcher.addOrder(
|
||||||
|
orderHash1,
|
||||||
|
signedOrder1.expirationUnixTimestampSec.times(MILISECONDS_IN_SECOND),
|
||||||
|
);
|
||||||
const expirationOrder = [orderHash1, orderHash2];
|
const expirationOrder = [orderHash1, orderHash2];
|
||||||
const expectToBeCalledOnce = false;
|
const expectToBeCalledOnce = false;
|
||||||
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
|
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
|
||||||
@ -154,7 +161,7 @@ describe('ExpirationWatcher', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
expirationWatcher.subscribe(callbackAsync);
|
expirationWatcher.subscribe(callbackAsync);
|
||||||
timer.tick(order2Lifetime * 1000);
|
timer.tick(order2Lifetime * MILISECONDS_IN_SECOND);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('emits events in correct order when expirations are equal', (done: DoneCallback) => {
|
it('emits events in correct order when expirations are equal', (done: DoneCallback) => {
|
||||||
@ -181,8 +188,14 @@ describe('ExpirationWatcher', () => {
|
|||||||
);
|
);
|
||||||
const orderHash1 = getOrderHashHex(signedOrder1);
|
const orderHash1 = getOrderHashHex(signedOrder1);
|
||||||
const orderHash2 = getOrderHashHex(signedOrder2);
|
const orderHash2 = getOrderHashHex(signedOrder2);
|
||||||
expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
|
expirationWatcher.addOrder(
|
||||||
expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
|
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 expirationOrder = orderHash1 < orderHash2 ? [orderHash1, orderHash2] : [orderHash2, orderHash1];
|
||||||
const expectToBeCalledOnce = false;
|
const expectToBeCalledOnce = false;
|
||||||
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
|
const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
|
||||||
@ -195,7 +208,7 @@ describe('ExpirationWatcher', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
expirationWatcher.subscribe(callbackAsync);
|
expirationWatcher.subscribe(callbackAsync);
|
||||||
timer.tick(order2Lifetime * 1000);
|
timer.tick(order2Lifetime * MILISECONDS_IN_SECOND);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,8 @@ import { provider } from './utils/web3_wrapper';
|
|||||||
before('migrate contracts', async function(): Promise<void> {
|
before('migrate contracts', async function(): Promise<void> {
|
||||||
// HACK: Since the migrations take longer then our global mocha timeout limit
|
// HACK: Since the migrations take longer then our global mocha timeout limit
|
||||||
// we manually increase it for this before hook.
|
// we manually increase it for this before hook.
|
||||||
this.timeout(20000);
|
const mochaTestTimeoutMs = 20000;
|
||||||
|
this.timeout(mochaTestTimeoutMs);
|
||||||
const txDefaults = {
|
const txDefaults = {
|
||||||
gas: devConstants.GAS_ESTIMATE,
|
gas: devConstants.GAS_ESTIMATE,
|
||||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||||
|
@ -269,8 +269,8 @@ describe('OrderWatcher', () => {
|
|||||||
});
|
});
|
||||||
it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
|
it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18);
|
const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18);
|
const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals);
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address,
|
makerToken.address,
|
||||||
takerToken.address,
|
takerToken.address,
|
||||||
|
@ -64,8 +64,8 @@ export class DocsInfo {
|
|||||||
finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => {
|
finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => {
|
||||||
const versionIntroducedIfExists = this._docsInfo.menuSubsectionToVersionWhenIntroduced[contractName];
|
const versionIntroducedIfExists = this._docsInfo.menuSubsectionToVersionWhenIntroduced[contractName];
|
||||||
if (!_.isUndefined(versionIntroducedIfExists)) {
|
if (!_.isUndefined(versionIntroducedIfExists)) {
|
||||||
const existsInSelectedVersion = compareVersions(selectedVersion, versionIntroducedIfExists) >= 0;
|
const doesExistInSelectedVersion = compareVersions(selectedVersion, versionIntroducedIfExists) >= 0;
|
||||||
return existsInSelectedVersion;
|
return doesExistInSelectedVersion;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"no-object-literal-type-assertion": false,
|
"no-object-literal-type-assertion": false,
|
||||||
"completed-docs": false,
|
"completed-docs": false,
|
||||||
"prefer-function-over-method": false
|
"prefer-function-over-method": false,
|
||||||
|
"custom-no-magic-numbers": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"no-object-literal-type-assertion": false,
|
"no-object-literal-type-assertion": false,
|
||||||
"completed-docs": 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}...`);
|
logUtils.log(`Downloading ${fullSolcVersion}...`);
|
||||||
const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`;
|
const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`;
|
||||||
const response = await fetch(url);
|
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}`);
|
throw new Error(`Failed to load ${fullSolcVersion}`);
|
||||||
}
|
}
|
||||||
solcjs = await response.text();
|
solcjs = await response.text();
|
||||||
|
@ -39,8 +39,13 @@ describe('#Compiler', function(): void {
|
|||||||
const exchangeArtifactString = await fsWrapper.readFileAsync(exchangeArtifactPath, opts);
|
const exchangeArtifactString = await fsWrapper.readFileAsync(exchangeArtifactPath, opts);
|
||||||
const exchangeArtifact: ContractArtifact = JSON.parse(exchangeArtifactString);
|
const exchangeArtifact: ContractArtifact = JSON.parse(exchangeArtifactString);
|
||||||
// The last 43 bytes of the binaries are metadata which may not be equivalent
|
// 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 metadataByteLength = 43;
|
||||||
const exchangeBinaryWithoutMetadata = exchange_binary.slice(0, -86);
|
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);
|
expect(unlinkedBinaryWithoutMetadata).to.equal(exchangeBinaryWithoutMetadata);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -40,12 +40,14 @@ describe('Collect coverage entries', () => {
|
|||||||
const coverageEntries = collectCoverageEntries(simpleStorageContract);
|
const coverageEntries = collectCoverageEntries(simpleStorageContract);
|
||||||
const fnIds = _.keys(coverageEntries.fnMap);
|
const fnIds = _.keys(coverageEntries.fnMap);
|
||||||
expect(coverageEntries.fnMap[fnIds[0]].name).to.be.equal('set');
|
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);
|
expect(coverageEntries.fnMap[fnIds[0]].line).to.be.equal(5);
|
||||||
const setFunction = `function set(uint x) {
|
const setFunction = `function set(uint x) {
|
||||||
storedData = x;
|
storedData = x;
|
||||||
}`;
|
}`;
|
||||||
expect(getRange(simpleStorageContract, coverageEntries.fnMap[fnIds[0]].loc)).to.be.equal(setFunction);
|
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]].name).to.be.equal('get');
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
expect(coverageEntries.fnMap[fnIds[1]].line).to.be.equal(8);
|
expect(coverageEntries.fnMap[fnIds[1]].line).to.be.equal(8);
|
||||||
const getFunction = `function get() constant returns (uint retVal) {
|
const getFunction = `function get() constant returns (uint retVal) {
|
||||||
return storedData;
|
return storedData;
|
||||||
@ -122,6 +124,7 @@ describe('Collect coverage entries', () => {
|
|||||||
|
|
||||||
const branchDescriptions = _.values(coverageEntries.branchMap);
|
const branchDescriptions = _.values(coverageEntries.branchMap);
|
||||||
const branchLines = _.map(branchDescriptions, branchDescription => branchDescription.line);
|
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]);
|
expect(branchLines).to.be.deep.equal([94, 115, 119, 130, 151, 187]);
|
||||||
const branchTypes = _.map(branchDescriptions, branchDescription => branchDescription.type);
|
const branchTypes = _.map(branchDescriptions, branchDescription => branchDescription.type);
|
||||||
expect(branchTypes).to.be.deep.equal(['if', 'if', 'if', 'if', 'binary-expr', 'if']);
|
expect(branchTypes).to.be.deep.equal(['if', 'if', 'if', 'if', 'binary-expr', 'if']);
|
||||||
|
@ -12,6 +12,7 @@ const expect = chai.expect;
|
|||||||
describe('instructions', () => {
|
describe('instructions', () => {
|
||||||
describe('#getPcToInstructionIndexMapping', () => {
|
describe('#getPcToInstructionIndexMapping', () => {
|
||||||
it('correctly maps pcs to instruction indexed', () => {
|
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 bytecode = new Uint8Array([constants.PUSH1, 42, constants.PUSH2, 1, 2, constants.TIMESTAMP]);
|
||||||
const pcToInstruction = getPcToInstructionIndexMapping(bytecode);
|
const pcToInstruction = getPcToInstructionIndexMapping(bytecode);
|
||||||
const expectedPcToInstruction = { '0': 0, '2': 1, '5': 2 };
|
const expectedPcToInstruction = { '0': 0, '2': 1, '5': 2 };
|
||||||
|
@ -13,7 +13,18 @@ import { postmanEnvironmentFactory } from './postman_environment_factory';
|
|||||||
import { utils } from './utils';
|
import { utils } from './utils';
|
||||||
|
|
||||||
const DEFAULT_NETWORK_ID = 1;
|
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
|
// extract command line arguments
|
||||||
const args = yargs
|
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';
|
import { addresses as ropstenAddresses } from './contract_addresses/ropsten_addresses';
|
||||||
|
|
||||||
const ENVIRONMENT_NAME = 'SRA Report';
|
const ENVIRONMENT_NAME = 'SRA Report';
|
||||||
|
const networkNameToId: { [networkName: string]: number } = {
|
||||||
|
mainnet: 1,
|
||||||
|
ropsten: 3,
|
||||||
|
rinkeby: 4,
|
||||||
|
kovan: 42,
|
||||||
|
};
|
||||||
|
|
||||||
export interface EnvironmentValue {
|
export interface EnvironmentValue {
|
||||||
key: string;
|
key: string;
|
||||||
@ -107,13 +113,13 @@ async function createOrderEnvironmentValuesAsync(url: string): Promise<Environme
|
|||||||
}
|
}
|
||||||
function getContractAddresses(networkId: number): Addresses {
|
function getContractAddresses(networkId: number): Addresses {
|
||||||
switch (networkId) {
|
switch (networkId) {
|
||||||
case 1:
|
case networkNameToId.mainnet:
|
||||||
return mainnetAddresses;
|
return mainnetAddresses;
|
||||||
case 3:
|
case networkNameToId.ropsten:
|
||||||
return ropstenAddresses;
|
return ropstenAddresses;
|
||||||
case 4:
|
case networkNameToId.rinkeby:
|
||||||
return rinkebyAddresses;
|
return rinkebyAddresses;
|
||||||
case 42:
|
case networkNameToId.kovan:
|
||||||
return kovanAddresses;
|
return kovanAddresses;
|
||||||
default:
|
default:
|
||||||
throw new Error('Unsupported network id');
|
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 CONTENT_TYPE_ASSERTION_NAME = 'Has Content-Type header with value application/json';
|
||||||
const SCHEMA_ASSERTION_NAME = 'Schema is valid';
|
const SCHEMA_ASSERTION_NAME = 'Schema is valid';
|
||||||
|
const SUCCESS_STATUS = 200;
|
||||||
const baseNewmanRunOptions = {
|
const baseNewmanRunOptions = {
|
||||||
collection: sraReportCollectionJSON,
|
collection: sraReportCollectionJSON,
|
||||||
environment: postmanEnvironmentJSON,
|
environment: postmanEnvironmentJSON,
|
||||||
@ -46,7 +47,7 @@ export const testRunner = {
|
|||||||
};
|
};
|
||||||
describe(CONTENT_TYPE_ASSERTION_NAME, () => {
|
describe(CONTENT_TYPE_ASSERTION_NAME, () => {
|
||||||
it('fails when there are no headers', async () => {
|
it('fails when there are no headers', async () => {
|
||||||
nockInterceptor.reply(200, {});
|
nockInterceptor.reply(SUCCESS_STATUS, {});
|
||||||
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
||||||
const error = findAssertionErrorIfExists(
|
const error = findAssertionErrorIfExists(
|
||||||
summary,
|
summary,
|
||||||
@ -61,7 +62,7 @@ export const testRunner = {
|
|||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'text/html',
|
'Content-Type': 'text/html',
|
||||||
};
|
};
|
||||||
nockInterceptor.reply(200, {}, headers);
|
nockInterceptor.reply(SUCCESS_STATUS, {}, headers);
|
||||||
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
||||||
const error = findAssertionErrorIfExists(
|
const error = findAssertionErrorIfExists(
|
||||||
summary,
|
summary,
|
||||||
@ -76,7 +77,7 @@ export const testRunner = {
|
|||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'charset=utf-8; application/json',
|
'Content-Type': 'charset=utf-8; application/json',
|
||||||
};
|
};
|
||||||
nockInterceptor.reply(200, {}, headers);
|
nockInterceptor.reply(SUCCESS_STATUS, {}, headers);
|
||||||
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
||||||
const error = findAssertionErrorIfExists(
|
const error = findAssertionErrorIfExists(
|
||||||
summary,
|
summary,
|
||||||
@ -100,7 +101,7 @@ export const testRunner = {
|
|||||||
};
|
};
|
||||||
describe(SCHEMA_ASSERTION_NAME, () => {
|
describe(SCHEMA_ASSERTION_NAME, () => {
|
||||||
it('fails when schema is invalid', async () => {
|
it('fails when schema is invalid', async () => {
|
||||||
nockInterceptor.reply(200, malformedJson);
|
nockInterceptor.reply(SUCCESS_STATUS, malformedJson);
|
||||||
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
||||||
const error = findAssertionErrorIfExists(summary, postmanCollectionRequestName, SCHEMA_ASSERTION_NAME);
|
const error = findAssertionErrorIfExists(summary, postmanCollectionRequestName, SCHEMA_ASSERTION_NAME);
|
||||||
const errorMessage = _.get(error, 'message');
|
const errorMessage = _.get(error, 'message');
|
||||||
@ -108,7 +109,7 @@ export const testRunner = {
|
|||||||
expect(errorMessage).to.equal('expected false to be true');
|
expect(errorMessage).to.equal('expected false to be true');
|
||||||
});
|
});
|
||||||
it('passes when schema is valid', async () => {
|
it('passes when schema is valid', async () => {
|
||||||
nockInterceptor.reply(200, correctJson);
|
nockInterceptor.reply(SUCCESS_STATUS, correctJson);
|
||||||
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
const summary = await utils.newmanRunAsync(newmanRunOptions);
|
||||||
const error = findAssertionErrorIfExists(summary, postmanCollectionRequestName, SCHEMA_ASSERTION_NAME);
|
const error = findAssertionErrorIfExists(summary, postmanCollectionRequestName, SCHEMA_ASSERTION_NAME);
|
||||||
const errorMessage = _.get(error, 'message');
|
const errorMessage = _.get(error, 'message');
|
||||||
|
@ -113,9 +113,12 @@ export class LedgerSubprovider extends BaseWalletSubprovider {
|
|||||||
const tx = new EthereumTx(txParams);
|
const tx = new EthereumTx(txParams);
|
||||||
|
|
||||||
// Set the EIP155 bits
|
// Set the EIP155 bits
|
||||||
tx.raw[6] = Buffer.from([this._networkId]); // v
|
const vIndex = 6;
|
||||||
tx.raw[7] = Buffer.from([]); // r
|
tx.raw[vIndex] = Buffer.from([this._networkId]); // v
|
||||||
tx.raw[8] = Buffer.from([]); // s
|
const rIndex = 7;
|
||||||
|
tx.raw[rIndex] = Buffer.from([]); // r
|
||||||
|
const sIndex = 8;
|
||||||
|
tx.raw[sIndex] = Buffer.from([]); // s
|
||||||
|
|
||||||
const txHex = tx.serialize().toString('hex');
|
const txHex = tx.serialize().toString('hex');
|
||||||
try {
|
try {
|
||||||
@ -127,7 +130,8 @@ export class LedgerSubprovider extends BaseWalletSubprovider {
|
|||||||
tx.v = Buffer.from(result.v, 'hex');
|
tx.v = Buffer.from(result.v, 'hex');
|
||||||
|
|
||||||
// EIP155: v should be chain_id * 2 + {35, 36}
|
// 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) {
|
if (signedChainId !== this._networkId) {
|
||||||
await this._destroyLedgerClientAsync();
|
await this._destroyLedgerClientAsync();
|
||||||
const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware);
|
const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware);
|
||||||
@ -169,8 +173,10 @@ export class LedgerSubprovider extends BaseWalletSubprovider {
|
|||||||
fullDerivationPath,
|
fullDerivationPath,
|
||||||
ethUtil.stripHexPrefix(data),
|
ethUtil.stripHexPrefix(data),
|
||||||
);
|
);
|
||||||
const v = result.v - 27;
|
const lowestValidV = 27;
|
||||||
let vHex = v.toString(16);
|
const v = result.v - lowestValidV;
|
||||||
|
const hexBase = 16;
|
||||||
|
let vHex = v.toString(hexBase);
|
||||||
if (vHex.length < 2) {
|
if (vHex.length < 2) {
|
||||||
vHex = `0${v}`;
|
vHex = `0${v}`;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,8 @@ export class NonceTrackerSubprovider extends Subprovider {
|
|||||||
// Increment the nonce from the previous successfully submitted transaction
|
// Increment the nonce from the previous successfully submitted transaction
|
||||||
let nonce = ethUtil.bufferToInt(transaction.nonce);
|
let nonce = ethUtil.bufferToInt(transaction.nonce);
|
||||||
nonce++;
|
nonce++;
|
||||||
let nextHexNonce = nonce.toString(16);
|
const hexBase = 16;
|
||||||
|
let nextHexNonce = nonce.toString(hexBase);
|
||||||
if (nextHexNonce.length % 2) {
|
if (nextHexNonce.length % 2) {
|
||||||
nextHexNonce = `0${nextHexNonce}`;
|
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
|
// Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
|
||||||
private static _getRandomId(): number {
|
private static _getRandomId(): number {
|
||||||
const extraDigits = 3;
|
const extraDigits = 3;
|
||||||
|
const baseTen = 10;
|
||||||
// 13 time digits
|
// 13 time digits
|
||||||
const datePart = new Date().getTime() * Math.pow(10, extraDigits);
|
const datePart = new Date().getTime() * Math.pow(baseTen, extraDigits);
|
||||||
// 3 random digits
|
// 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
|
// 16 digits
|
||||||
return datePart + extraPart;
|
return datePart + extraPart;
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,10 @@ class DerivedHDKeyInfoIterator implements IterableIterator<DerivedHDKeyInfo> {
|
|||||||
baseDerivationPath,
|
baseDerivationPath,
|
||||||
derivationPath: fullDerivationPath,
|
derivationPath: fullDerivationPath,
|
||||||
};
|
};
|
||||||
const done = this._index === this._searchLimit;
|
const isDone = this._index === this._searchLimit;
|
||||||
this._index++;
|
this._index++;
|
||||||
return {
|
return {
|
||||||
done,
|
done: isDone,
|
||||||
value: derivedKey,
|
value: derivedKey,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
|
|||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
const DEFAULT_NUM_ACCOUNTS = 10;
|
||||||
|
const EXPECTED_SIGNATURE_LENGTH = 132;
|
||||||
|
|
||||||
async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumClient> {
|
async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumClient> {
|
||||||
const ledgerConnection = await TransportNodeHid.create();
|
const ledgerConnection = await TransportNodeHid.create();
|
||||||
@ -41,7 +43,7 @@ describe('LedgerSubprovider', () => {
|
|||||||
it('returns default number of accounts', async () => {
|
it('returns default number of accounts', async () => {
|
||||||
const accounts = await ledgerSubprovider.getAccountsAsync();
|
const accounts = await ledgerSubprovider.getAccountsAsync();
|
||||||
expect(accounts[0]).to.not.be.an('undefined');
|
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 () => {
|
it('returns the expected accounts from a ledger set up with the test mnemonic', async () => {
|
||||||
const accounts = await ledgerSubprovider.getAccountsAsync();
|
const accounts = await ledgerSubprovider.getAccountsAsync();
|
||||||
@ -105,7 +107,7 @@ describe('LedgerSubprovider', () => {
|
|||||||
};
|
};
|
||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
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();
|
done();
|
||||||
});
|
});
|
||||||
ledgerProvider.sendAsync(payload, callback);
|
ledgerProvider.sendAsync(payload, callback);
|
||||||
@ -123,7 +125,7 @@ describe('LedgerSubprovider', () => {
|
|||||||
};
|
};
|
||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
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');
|
expect(response.result.substr(0, 2)).to.be.equal('0x');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -143,7 +145,7 @@ describe('LedgerSubprovider', () => {
|
|||||||
};
|
};
|
||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
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');
|
expect(response.result.substr(0, 2)).to.be.equal('0x');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -197,7 +199,8 @@ describe('LedgerSubprovider', () => {
|
|||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
expect(err).to.be.a('null');
|
||||||
const result = response.result;
|
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');
|
expect(result.substr(0, 2)).to.be.equal('0x');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -21,6 +21,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
|
|||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const FAKE_ADDRESS = '0xb088a3bc93f71b4de97b9de773e9647645983688';
|
const FAKE_ADDRESS = '0xb088a3bc93f71b4de97b9de773e9647645983688';
|
||||||
|
const DEFAULT_NUM_ACCOUNTS = 10;
|
||||||
|
|
||||||
describe('LedgerSubprovider', () => {
|
describe('LedgerSubprovider', () => {
|
||||||
const networkId: number = 42;
|
const networkId: number = 42;
|
||||||
@ -73,7 +74,7 @@ describe('LedgerSubprovider', () => {
|
|||||||
it('returns default number of accounts', async () => {
|
it('returns default number of accounts', async () => {
|
||||||
const accounts = await ledgerSubprovider.getAccountsAsync();
|
const accounts = await ledgerSubprovider.getAccountsAsync();
|
||||||
expect(accounts[0]).to.be.equal(FAKE_ADDRESS);
|
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 () => {
|
it('returns requested number of accounts', async () => {
|
||||||
const numberOfAccounts = 20;
|
const numberOfAccounts = 20;
|
||||||
@ -119,7 +120,7 @@ describe('LedgerSubprovider', () => {
|
|||||||
};
|
};
|
||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
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);
|
expect(response.result[0]).to.be.equal(FAKE_ADDRESS);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -176,7 +177,8 @@ describe('LedgerSubprovider', () => {
|
|||||||
};
|
};
|
||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
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');
|
expect(response.result.raw.substr(0, 2)).to.be.equal('0x');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
|
|||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
const DEFAULT_NUM_ACCOUNTS = 10;
|
||||||
|
|
||||||
describe('MnemonicWalletSubprovider', () => {
|
describe('MnemonicWalletSubprovider', () => {
|
||||||
let subprovider: MnemonicWalletSubprovider;
|
let subprovider: MnemonicWalletSubprovider;
|
||||||
@ -33,7 +34,7 @@ describe('MnemonicWalletSubprovider', () => {
|
|||||||
const accounts = await subprovider.getAccountsAsync();
|
const accounts = await subprovider.getAccountsAsync();
|
||||||
expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
|
expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
|
||||||
expect(accounts[1]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_1);
|
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 () => {
|
it('signs a personal message', async () => {
|
||||||
const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
|
const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
|
||||||
@ -90,7 +91,7 @@ describe('MnemonicWalletSubprovider', () => {
|
|||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
expect(err).to.be.a('null');
|
||||||
expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
|
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();
|
done();
|
||||||
});
|
});
|
||||||
provider.sendAsync(payload, callback);
|
provider.sendAsync(payload, callback);
|
||||||
|
@ -14,6 +14,7 @@ import { reportCallbackErrors } from '../utils/report_callback_errors';
|
|||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
const DEFAULT_NUM_ACCOUNTS = 10;
|
||||||
|
|
||||||
describe('RedundantSubprovider', () => {
|
describe('RedundantSubprovider', () => {
|
||||||
let provider: Web3ProviderEngine;
|
let provider: Web3ProviderEngine;
|
||||||
@ -32,7 +33,7 @@ describe('RedundantSubprovider', () => {
|
|||||||
};
|
};
|
||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
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();
|
done();
|
||||||
});
|
});
|
||||||
provider.sendAsync(payload, callback);
|
provider.sendAsync(payload, callback);
|
||||||
@ -55,7 +56,7 @@ describe('RedundantSubprovider', () => {
|
|||||||
};
|
};
|
||||||
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
|
||||||
expect(err).to.be.a('null');
|
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();
|
done();
|
||||||
});
|
});
|
||||||
provider.sendAsync(payload, callback);
|
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 RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
||||||
|
|
||||||
import { configs } from './configs';
|
import { configs } from './configs';
|
||||||
|
import { constants } from './constants';
|
||||||
import { DispatchQueue } from './dispatch_queue';
|
import { DispatchQueue } from './dispatch_queue';
|
||||||
import { dispenseAssetTasks } from './dispense_asset_tasks';
|
import { dispenseAssetTasks } from './dispense_asset_tasks';
|
||||||
import { rpcUrls } from './rpc_urls';
|
import { rpcUrls } from './rpc_urls';
|
||||||
@ -80,7 +81,7 @@ export class Handler {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
const payload = JSON.stringify(queueInfo);
|
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 {
|
public dispenseEther(req: express.Request, res: express.Response): void {
|
||||||
this._dispenseAsset(req, res, RequestedAssetType.ETH);
|
this._dispenseAsset(req, res, RequestedAssetType.ETH);
|
||||||
@ -120,11 +121,11 @@ export class Handler {
|
|||||||
}
|
}
|
||||||
const didAddToQueue = networkConfig.dispatchQueue.add(dispenserTask);
|
const didAddToQueue = networkConfig.dispatchQueue.add(dispenserTask);
|
||||||
if (!didAddToQueue) {
|
if (!didAddToQueue) {
|
||||||
res.status(503).send('QUEUE_IS_FULL');
|
res.status(constants.SERVICE_UNAVAILABLE_STATUS).send('QUEUE_IS_FULL');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logUtils.log(`Added ${recipient} to queue: ${requestedAssetType} networkId: ${networkId}`);
|
logUtils.log(`Added ${recipient} to queue: ${requestedAssetType} networkId: ${networkId}`);
|
||||||
res.status(200).end();
|
res.status(constants.SUCCESS_STATUS).end();
|
||||||
}
|
}
|
||||||
private async _dispenseOrderAsync(
|
private async _dispenseOrderAsync(
|
||||||
req: express.Request,
|
req: express.Request,
|
||||||
@ -133,7 +134,7 @@ export class Handler {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const networkConfig = _.get(this._networkConfigByNetworkId, req.params.networkId);
|
const networkConfig = _.get(this._networkConfigByNetworkId, req.params.networkId);
|
||||||
if (_.isUndefined(networkConfig)) {
|
if (_.isUndefined(networkConfig)) {
|
||||||
res.status(400).send('UNSUPPORTED_NETWORK_ID');
|
res.status(constants.BAD_REQUEST_STATUS).send('UNSUPPORTED_NETWORK_ID');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const zeroEx = networkConfig.zeroEx;
|
const zeroEx = networkConfig.zeroEx;
|
||||||
@ -173,6 +174,6 @@ export class Handler {
|
|||||||
const signedOrderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const signedOrderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const payload = JSON.stringify(signedOrder);
|
const payload = JSON.stringify(signedOrder);
|
||||||
logUtils.log(`Dispensed signed order: ${payload}`);
|
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 * as _ from 'lodash';
|
||||||
|
|
||||||
import { configs } from './configs';
|
import { configs } from './configs';
|
||||||
|
import { constants } from './constants';
|
||||||
import { rpcUrls } from './rpc_urls';
|
import { rpcUrls } from './rpc_urls';
|
||||||
|
|
||||||
const DEFAULT_NETWORK_ID = 42; // kovan
|
const DEFAULT_NETWORK_ID = 42; // kovan
|
||||||
@ -11,7 +12,7 @@ export const parameterTransformer = {
|
|||||||
transform(req: Request, res: Response, next: NextFunction): void {
|
transform(req: Request, res: Response, next: NextFunction): void {
|
||||||
const recipientAddress = req.params.recipient;
|
const recipientAddress = req.params.recipient;
|
||||||
if (_.isUndefined(recipientAddress) || !addressUtils.isAddress(recipientAddress)) {
|
if (_.isUndefined(recipientAddress) || !addressUtils.isAddress(recipientAddress)) {
|
||||||
res.status(400).send('INVALID_RECIPIENT_ADDRESS');
|
res.status(constants.BAD_REQUEST_STATUS).send('INVALID_RECIPIENT_ADDRESS');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
||||||
@ -19,7 +20,7 @@ export const parameterTransformer = {
|
|||||||
const networkId = _.get(req.query, 'networkId', DEFAULT_NETWORK_ID);
|
const networkId = _.get(req.query, 'networkId', DEFAULT_NETWORK_ID);
|
||||||
const rpcUrlIfExists = _.get(rpcUrls, networkId);
|
const rpcUrlIfExists = _.get(rpcUrls, networkId);
|
||||||
if (_.isUndefined(rpcUrlIfExists)) {
|
if (_.isUndefined(rpcUrlIfExists)) {
|
||||||
res.status(400).send('UNSUPPORTED_NETWORK_ID');
|
res.status(constants.BAD_REQUEST_STATUS).send('UNSUPPORTED_NETWORK_ID');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
req.params.networkId = networkId;
|
req.params.networkId = networkId;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as bodyParser from 'body-parser';
|
import * as bodyParser from 'body-parser';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
|
|
||||||
|
import { constants } from './constants';
|
||||||
import { errorReporter } from './error_reporter';
|
import { errorReporter } from './error_reporter';
|
||||||
import { Handler } from './handler';
|
import { Handler } from './handler';
|
||||||
import { parameterTransformer } from './parameter_transformer';
|
import { parameterTransformer } from './parameter_transformer';
|
||||||
@ -18,7 +19,7 @@ app.use((req, res, next) => {
|
|||||||
|
|
||||||
const handler = new Handler();
|
const handler = new Handler();
|
||||||
app.get('/ping', (req: express.Request, res: express.Response) => {
|
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('/info', handler.getQueueInfo.bind(handler));
|
||||||
app.get('/ether/:recipient', parameterTransformer.transform, handler.dispenseEther.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
|
// Log to rollbar any errors unhandled by handlers
|
||||||
app.use(errorReporter.errorHandler());
|
app.use(errorReporter.errorHandler());
|
||||||
const port = process.env.PORT || 3000;
|
const DEFAULT_PORT = 3000;
|
||||||
|
const port = process.env.PORT || DEFAULT_PORT;
|
||||||
app.listen(port);
|
app.listen(port);
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"tslint": "5.8.0",
|
"tslint": "5.8.0",
|
||||||
"tslint-eslint-rules": "^4.1.1",
|
"tslint-eslint-rules": "^4.1.1",
|
||||||
"tslint-react": "^3.2.0"
|
"tslint-react": "^3.2.0",
|
||||||
|
"tsutils": "^2.12.1"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"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-parens": [true, "ban-single-arg-parens"],
|
||||||
"arrow-return-shorthand": true,
|
"arrow-return-shorthand": true,
|
||||||
"async-suffix": true,
|
"async-suffix": true,
|
||||||
|
"boolean-naming": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
"await-promise": true,
|
"await-promise": true,
|
||||||
|
"custom-no-magic-numbers": [true, 0, 1, 2, 3, -1],
|
||||||
"binary-expression-operand-order": true,
|
"binary-expression-operand-order": true,
|
||||||
"callable-types": true,
|
"callable-types": true,
|
||||||
"class-name": true,
|
"class-name": true,
|
||||||
|
@ -23,7 +23,8 @@ export class AbiDecoder {
|
|||||||
formatted = formatted.slice(2);
|
formatted = formatted.slice(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
formatted = _.padStart(formatted, 40, '0');
|
const addressLength = 40;
|
||||||
|
formatted = _.padStart(formatted, addressLength, '0');
|
||||||
return `0x${formatted}`;
|
return `0x${formatted}`;
|
||||||
}
|
}
|
||||||
constructor(abiArrays: AbiDefinition[][]) {
|
constructor(abiArrays: AbiDefinition[][]) {
|
||||||
@ -45,16 +46,17 @@ export class AbiDecoder {
|
|||||||
const dataTypes = _.map(nonIndexedInputs, input => input.type);
|
const dataTypes = _.map(nonIndexedInputs, input => input.type);
|
||||||
const decodedData = ethersInterface.events[event.name].parse(log.data);
|
const decodedData = ethersInterface.events[event.name].parse(log.data);
|
||||||
|
|
||||||
let failedToDecode = false;
|
let didFailToDecode = false;
|
||||||
_.forEach(event.inputs, (param: EventParameter, i: number) => {
|
_.forEach(event.inputs, (param: EventParameter, i: number) => {
|
||||||
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
||||||
let value: BigNumber | string | number = param.indexed ? log.topics[topicsIndex++] : decodedData[i];
|
let value: BigNumber | string | number = param.indexed ? log.topics[topicsIndex++] : decodedData[i];
|
||||||
if (_.isUndefined(value)) {
|
if (_.isUndefined(value)) {
|
||||||
failedToDecode = true;
|
didFailToDecode = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (param.type === SolidityTypes.Address) {
|
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) {
|
} else if (param.type === SolidityTypes.Uint256 || param.type === SolidityTypes.Uint) {
|
||||||
value = new BigNumber(value);
|
value = new BigNumber(value);
|
||||||
} else if (param.type === SolidityTypes.Uint8) {
|
} else if (param.type === SolidityTypes.Uint8) {
|
||||||
@ -63,7 +65,7 @@ export class AbiDecoder {
|
|||||||
decodedParams[param.name] = value;
|
decodedParams[param.name] = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (failedToDecode) {
|
if (didFailToDecode) {
|
||||||
return log;
|
return log;
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
@ -9,11 +9,16 @@ export const addressUtils = {
|
|||||||
const unprefixedAddress = address.replace('0x', '');
|
const unprefixedAddress = address.replace('0x', '');
|
||||||
const addressHash = jsSHA3.keccak256(unprefixedAddress.toLowerCase());
|
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
|
// The nth letter should be uppercase if the nth digit of casemap is 1
|
||||||
|
const hexBase = 16;
|
||||||
|
const lowercaseRange = 7;
|
||||||
if (
|
if (
|
||||||
(parseInt(addressHash[i], 16) > 7 && unprefixedAddress[i].toUpperCase() !== unprefixedAddress[i]) ||
|
(parseInt(addressHash[i], hexBase) > lowercaseRange &&
|
||||||
(parseInt(addressHash[i], 16) <= 7 && unprefixedAddress[i].toLowerCase() !== unprefixedAddress[i])
|
unprefixedAddress[i].toUpperCase() !== unprefixedAddress[i]) ||
|
||||||
|
(parseInt(addressHash[i], hexBase) <= lowercaseRange &&
|
||||||
|
unprefixedAddress[i].toLowerCase() !== unprefixedAddress[i])
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,18 @@ export const intervalUtils = {
|
|||||||
intervalMs: number,
|
intervalMs: number,
|
||||||
onError: (err: Error) => void,
|
onError: (err: Error) => void,
|
||||||
): NodeJS.Timer {
|
): NodeJS.Timer {
|
||||||
let locked = false;
|
let isLocked = false;
|
||||||
const intervalId = setInterval(async () => {
|
const intervalId = setInterval(async () => {
|
||||||
if (locked) {
|
if (isLocked) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
locked = true;
|
isLocked = true;
|
||||||
try {
|
try {
|
||||||
await fn();
|
await fn();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
onError(err);
|
onError(err);
|
||||||
}
|
}
|
||||||
locked = false;
|
isLocked = false;
|
||||||
}
|
}
|
||||||
}, intervalMs);
|
}, intervalMs);
|
||||||
return intervalId;
|
return intervalId;
|
||||||
|
@ -19,6 +19,8 @@ import * as Web3 from 'web3';
|
|||||||
|
|
||||||
import { Web3WrapperErrors } from './types';
|
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.
|
* 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.
|
* @return The amount in units.
|
||||||
*/
|
*/
|
||||||
public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber {
|
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);
|
const unit = amount.div(aUnit);
|
||||||
return unit;
|
return unit;
|
||||||
}
|
}
|
||||||
@ -61,7 +63,7 @@ export class Web3Wrapper {
|
|||||||
* @return The amount in baseUnits.
|
* @return The amount in baseUnits.
|
||||||
*/
|
*/
|
||||||
public static toBaseUnitAmount(amount: BigNumber, decimals: number): BigNumber {
|
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 baseUnitAmount = amount.times(unit);
|
||||||
const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
|
const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
|
||||||
if (hasDecimals) {
|
if (hasDecimals) {
|
||||||
@ -180,8 +182,8 @@ export class Web3Wrapper {
|
|||||||
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
|
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
|
||||||
const code = await promisify<string>(this._web3.eth.getCode)(address);
|
const code = await promisify<string>(this._web3.eth.getCode)(address);
|
||||||
// Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients
|
// Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients
|
||||||
const codeIsEmpty = /^0x0{0,40}$/i.test(code);
|
const isCodeEmpty = /^0x0{0,40}$/i.test(code);
|
||||||
return !codeIsEmpty;
|
return !isCodeEmpty;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sign a message with a specific address's private key (`eth_sign`)
|
* Sign a message with a specific address's private key (`eth_sign`)
|
||||||
@ -336,16 +338,16 @@ export class Web3Wrapper {
|
|||||||
pollingIntervalMs: number = 1000,
|
pollingIntervalMs: number = 1000,
|
||||||
timeoutMs?: number,
|
timeoutMs?: number,
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
let timeoutExceeded = false;
|
let wasTimeoutExceeded = false;
|
||||||
if (timeoutMs) {
|
if (timeoutMs) {
|
||||||
setTimeout(() => (timeoutExceeded = true), timeoutMs);
|
setTimeout(() => (wasTimeoutExceeded = true), timeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const txReceiptPromise = new Promise(
|
const txReceiptPromise = new Promise(
|
||||||
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
|
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
|
||||||
const intervalId = intervalUtils.setAsyncExcludingInterval(
|
const intervalId = intervalUtils.setAsyncExcludingInterval(
|
||||||
async () => {
|
async () => {
|
||||||
if (timeoutExceeded) {
|
if (wasTimeoutExceeded) {
|
||||||
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||||
return reject(Web3WrapperErrors.TransactionMiningTimeout);
|
return reject(Web3WrapperErrors.TransactionMiningTimeout);
|
||||||
}
|
}
|
||||||
|
@ -157,14 +157,14 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
const maxLength = 30;
|
const maxLength = 30;
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
const tokens = _.values(this.props.tokenByAddress);
|
||||||
const tokenWithNameIfExists = _.find(tokens, { name });
|
const tokenWithNameIfExists = _.find(tokens, { name });
|
||||||
const tokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
|
const doesTokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
|
||||||
if (name === '') {
|
if (name === '') {
|
||||||
nameErrText = 'Name is required';
|
nameErrText = 'Name is required';
|
||||||
} else if (!this._isValidName(name)) {
|
} else if (!this._isValidName(name)) {
|
||||||
nameErrText = 'Name should only contain letters, digits and spaces';
|
nameErrText = 'Name should only contain letters, digits and spaces';
|
||||||
} else if (name.length > maxLength) {
|
} else if (name.length > maxLength) {
|
||||||
nameErrText = `Max length is ${maxLength}`;
|
nameErrText = `Max length is ${maxLength}`;
|
||||||
} else if (tokenWithNameExists) {
|
} else if (doesTokenWithNameExists) {
|
||||||
nameErrText = 'Token with this name already exists';
|
nameErrText = 'Token with this name already exists';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,14 +177,14 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
let symbolErrText = '';
|
let symbolErrText = '';
|
||||||
const maxLength = 5;
|
const maxLength = 5;
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
const tokens = _.values(this.props.tokenByAddress);
|
||||||
const tokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol }));
|
const doesTokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol }));
|
||||||
if (symbol === '') {
|
if (symbol === '') {
|
||||||
symbolErrText = 'Symbol is required';
|
symbolErrText = 'Symbol is required';
|
||||||
} else if (!this._isAlphanumeric(symbol)) {
|
} else if (!this._isAlphanumeric(symbol)) {
|
||||||
symbolErrText = 'Can only include alphanumeric characters';
|
symbolErrText = 'Can only include alphanumeric characters';
|
||||||
} else if (symbol.length > maxLength) {
|
} else if (symbol.length > maxLength) {
|
||||||
symbolErrText = `Max length is ${maxLength}`;
|
symbolErrText = `Max length is ${maxLength}`;
|
||||||
} else if (tokenWithSymbolExists) {
|
} else if (doesTokenWithSymbolExists) {
|
||||||
symbolErrText = 'Token with symbol already exists';
|
symbolErrText = 'Token with symbol already exists';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,8 +56,8 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
|
|||||||
this._isUnmounted = true;
|
this._isUnmounted = true;
|
||||||
}
|
}
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const readyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
|
const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
|
||||||
if (!readyToRender) {
|
if (!isReadyToRender) {
|
||||||
return (
|
return (
|
||||||
<div className="col col-12" style={{ ...styles.root, height: '100%' }}>
|
<div className="col col-12" style={{ ...styles.root, height: '100%' }}>
|
||||||
<div
|
<div
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"no-implicit-dependencies": false,
|
"no-implicit-dependencies": false,
|
||||||
"no-object-literal-type-assertion": false,
|
"no-object-literal-type-assertion": false,
|
||||||
"completed-docs": 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