Merge branch 'master' into remainingTokenMethods

# Conflicts:
#	src/types.ts
#	src/web3_wrapper.ts
This commit is contained in:
Fabio Berger
2017-06-02 19:45:57 +02:00
22 changed files with 1366 additions and 293 deletions

View File

@@ -4,7 +4,7 @@ machine:
test:
override:
- node node_modules/ethereumjs-testrpc/bin/testrpc -m "concert load couple harbor equip island argue ramp clarify fence smart topic":
- npm run testrpc:
background: true
- git clone git@github.com:0xProject/contracts.git ../contracts
- cd ../contracts; git checkout 38c2b4c; npm install && npm run migrate

View File

@@ -12,7 +12,7 @@
"scripts": {
"prebuild": "npm run clean",
"build": "run-p build:*:prod",
"lint": "tslint src/**/*.ts",
"lint": "tslint src/*.ts test/*.ts",
"test": "run-s clean test:commonjs",
"test:umd": "run-s substitute_umd_bundle run_mocha; npm run clean",
"test:coverage": "nyc npm run test --all",
@@ -30,7 +30,7 @@
"pretest:umd": "run-s clean build:*:dev",
"substitute_umd_bundle": "npm run remove_src_files_not_used_by_tests; shx mv _bundles/* lib/src",
"remove_src_files_not_used_by_tests": "find ./lib/src \\( -path ./lib/src/utils -o -path ./lib/src/schemas -o -path \"./lib/src/types.*\" \\) -prune -o -type f -print | xargs rm",
"run_mocha": "mocha lib/test/**/*_test.js"
"run_mocha": "mocha lib/test/**/*_test.js --timeout 3000"
},
"config": {
"artifacts": "Proxy Exchange TokenRegistry Token Mintable EtherToken",
@@ -46,8 +46,6 @@
},
"devDependencies": {
"@types/bignumber.js": "^4.0.2",
"@types/chai": "^3.5.2",
"@types/chai-as-promised": "0.0.30",
"@types/jsonschema": "^1.1.1",
"@types/lodash": "^4.14.64",
"@types/mocha": "^2.2.41",
@@ -57,8 +55,11 @@
"bignumber.js": "^4.0.2",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"chai-as-promised-typescript-typings": "0.0.2",
"chai-bignumber": "^2.0.0",
"chai-typescript-typings": "^0.0.0",
"copyfiles": "^1.2.0",
"dirty-chai": "^1.2.2",
"ethereumjs-testrpc": "3.0.5",
"json-loader": "^0.5.4",
"mocha": "^3.4.1",

View File

@@ -1,70 +1,38 @@
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
import {bigNumberConfigs} from './bignumber_config';
import * as ethUtil from 'ethereumjs-util';
import contract = require('truffle-contract');
import * as Web3 from 'web3';
import * as ethABI from 'ethereumjs-abi';
import findVersions = require('find-versions');
import compareVersions = require('compare-versions');
import {Web3Wrapper} from './web3_wrapper';
import {constants} from './utils/constants';
import {utils} from './utils/utils';
import {assert} from './utils/assert';
import findVersions = require('find-versions');
import compareVersions = require('compare-versions');
import {SchemaValidator} from './utils/schema_validator';
import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper';
import {TokenRegistryWrapper} from './contract_wrappers/token_registry_wrapper';
import {ecSignatureSchema} from './schemas/ec_signature_schema';
import {TokenWrapper} from './contract_wrappers/token_wrapper';
import {SolidityTypes, ECSignature, ZeroExError} from './types';
import {Order} from './types';
import {orderSchema} from './schemas/order_schemas';
import * as ExchangeArtifacts from './artifacts/Exchange.json';
// Customize our BigNumber instances
bigNumberConfigs.configure();
const MAX_DIGITS_IN_UNSIGNED_256_INT = 78;
export class ZeroEx {
public static NULL_ADDRESS = constants.NULL_ADDRESS;
public exchange: ExchangeWrapper;
public tokenRegistry: TokenRegistryWrapper;
public token: TokenWrapper;
private web3Wrapper: Web3Wrapper;
/**
* Computes the orderHash given the order parameters and returns it as a hex encoded string.
*/
public static getOrderHashHex(exchangeContractAddr: string, makerAddr: string, takerAddr: string,
tokenMAddress: string, tokenTAddress: string, feeRecipient: string,
valueM: BigNumber.BigNumber, valueT: BigNumber.BigNumber,
makerFee: BigNumber.BigNumber, takerFee: BigNumber.BigNumber,
expiration: BigNumber.BigNumber, salt: BigNumber.BigNumber): string {
takerAddr = _.isEmpty(takerAddr) ? constants.NULL_ADDRESS : takerAddr ;
assert.isETHAddressHex('exchangeContractAddr', exchangeContractAddr);
assert.isETHAddressHex('makerAddr', makerAddr);
assert.isETHAddressHex('takerAddr', takerAddr);
assert.isETHAddressHex('tokenMAddress', tokenMAddress);
assert.isETHAddressHex('tokenTAddress', tokenTAddress);
assert.isETHAddressHex('feeRecipient', feeRecipient);
assert.isBigNumber('valueM', valueM);
assert.isBigNumber('valueT', valueT);
assert.isBigNumber('makerFee', makerFee);
assert.isBigNumber('takerFee', takerFee);
assert.isBigNumber('expiration', expiration);
assert.isBigNumber('salt', salt);
const orderParts = [
{value: exchangeContractAddr, type: SolidityTypes.address},
{value: makerAddr, type: SolidityTypes.address},
{value: takerAddr, type: SolidityTypes.address},
{value: tokenMAddress, type: SolidityTypes.address},
{value: tokenTAddress, type: SolidityTypes.address},
{value: feeRecipient, type: SolidityTypes.address},
{value: utils.bigNumberToBN(valueM), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(valueT), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(makerFee), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(takerFee), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(expiration), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(salt), type: SolidityTypes.uint256},
];
const types = _.map(orderParts, o => o.type);
const values = _.map(orderParts, o => o.value);
const hashBuff = ethABI.soliditySHA3(types, values);
const hashHex = ethUtil.bufferToHex(hashBuff);
return hashHex;
}
/**
* Verifies that the elliptic curve signature `signature` was generated
* by signing `data` with the private key corresponding to the `signerAddressHex` address.
@@ -135,9 +103,9 @@ export class ZeroEx {
}
constructor(web3: Web3) {
this.web3Wrapper = new Web3Wrapper(web3);
this.exchange = new ExchangeWrapper(this.web3Wrapper);
this.tokenRegistry = new TokenRegistryWrapper(this.web3Wrapper);
this.token = new TokenWrapper(this.web3Wrapper);
this.exchange = new ExchangeWrapper(this.web3Wrapper, this.token);
this.tokenRegistry = new TokenRegistryWrapper(this.web3Wrapper);
}
/**
* Sets a new provider for the web3 instance used by 0x.js
@@ -148,6 +116,48 @@ export class ZeroEx {
this.tokenRegistry.invalidateContractInstance();
this.token.invalidateContractInstances();
}
/**
* Sets default account for sending transactions.
*/
public setTransactionSenderAccount(account: string): void {
this.web3Wrapper.setDefaultAccount(account);
}
/**
* Get the default account set for sending transactions.
*/
public async getTransactionSenderAccountIfExistsAsync(): Promise<string|undefined> {
const senderAccountIfExists = await this.web3Wrapper.getSenderAddressIfExistsAsync();
return senderAccountIfExists;
}
/**
* Computes the orderHash for a given order and returns it as a hex encoded string.
*/
public async getOrderHashHexAsync(order: Order): Promise<string> {
const exchangeContractAddr = await this.getExchangeAddressAsync();
assert.doesConformToSchema('order',
SchemaValidator.convertToJSONSchemaCompatibleObject(order as object),
orderSchema);
const orderParts = [
{value: exchangeContractAddr, type: SolidityTypes.address},
{value: order.maker, type: SolidityTypes.address},
{value: order.taker, type: SolidityTypes.address},
{value: order.makerTokenAddress, type: SolidityTypes.address},
{value: order.takerTokenAddress, type: SolidityTypes.address},
{value: order.feeRecipient, type: SolidityTypes.address},
{value: utils.bigNumberToBN(order.makerTokenAmount), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.takerTokenAmount), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.makerFee), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.takerFee), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.expirationUnixTimestampSec), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.salt), type: SolidityTypes.uint256},
];
const types = _.map(orderParts, o => o.type);
const values = _.map(orderParts, o => o.value);
const hashBuff = ethABI.soliditySHA3(types, values);
const hashHex = ethUtil.bufferToHex(hashBuff);
return hashHex;
}
/**
* Signs an orderHash and returns it's elliptic curve signature
* This method currently supports TestRPC, Geth and Parity above and below V1.6.6
@@ -155,6 +165,8 @@ export class ZeroEx {
public async signOrderHashAsync(orderHashHex: string): Promise<ECSignature> {
assert.isHexString('orderHashHex', orderHashHex);
const makerAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
let msgHashHex;
const nodeVersion = await this.web3Wrapper.getNodeVersionAsync();
const isParityNode = utils.isParityNode(nodeVersion);
@@ -167,12 +179,7 @@ export class ZeroEx {
msgHashHex = ethUtil.bufferToHex(msgHashBuff);
}
const makerAddressIfExists = await this.web3Wrapper.getSenderAddressIfExistsAsync();
if (_.isUndefined(makerAddressIfExists)) {
throw new Error(ZeroExError.USER_HAS_NO_ASSOCIATED_ADDRESSES);
}
const signature = await this.web3Wrapper.signTransactionAsync(makerAddressIfExists, msgHashHex);
const signature = await this.web3Wrapper.signTransactionAsync(makerAddress, msgHashHex);
let signatureData;
const [nodeVersionNumber] = findVersions(nodeVersion);
@@ -202,10 +209,21 @@ export class ZeroEx {
r: ethUtil.bufferToHex(r),
s: ethUtil.bufferToHex(s),
};
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, ecSignature, makerAddressIfExists);
const isValidSignature = ZeroEx.isValidSignature(orderHashHex, ecSignature, makerAddress);
if (!isValidSignature) {
throw new Error(ZeroExError.INVALID_SIGNATURE);
}
return ecSignature;
}
private async getExchangeAddressAsync() {
const networkIdIfExists = await this.web3Wrapper.getNetworkIdIfExistsAsync();
const exchangeNetworkConfigsIfExists = _.isUndefined(networkIdIfExists) ?
undefined :
(ExchangeArtifacts as any).networks[networkIdIfExists];
if (_.isUndefined(exchangeNetworkConfigsIfExists)) {
throw new Error(ZeroExError.CONTRACT_NOT_DEPLOYED_ON_NETWORK);
}
const exchangeAddress = exchangeNetworkConfigsIfExists.address;
return exchangeAddress;
}
}

11
src/bignumber_config.ts Normal file
View File

@@ -0,0 +1,11 @@
import * as BigNumber from 'bignumber.js';
export const bigNumberConfigs = {
configure() {
// By default BigNumber's `toString` method converts to exponential notation if the value has
// more then 20 digits. We want to avoid this behavior, so we set EXPONENTIAL_AT to a high number
BigNumber.config({
EXPONENTIAL_AT: 1000,
});
},
};

View File

@@ -1,15 +1,39 @@
import * as _ from 'lodash';
import {Web3Wrapper} from '../web3_wrapper';
import {ECSignature, ZeroExError, ExchangeContract} from '../types';
import {
ECSignature,
ExchangeContract,
ExchangeContractErrCodes,
ExchangeContractErrs,
OrderValues,
OrderAddresses,
SignedOrder,
ContractEvent,
ContractResponse,
} from '../types';
import {assert} from '../utils/assert';
import {ContractWrapper} from './contract_wrapper';
import * as ExchangeArtifacts from '../artifacts/Exchange.json';
import {ecSignatureSchema} from '../schemas/ec_signature_schema';
import {signedOrderSchema} from '../schemas/order_schemas';
import {SchemaValidator} from '../utils/schema_validator';
import {constants} from '../utils/constants';
import {TokenWrapper} from './token_wrapper';
export class ExchangeWrapper extends ContractWrapper {
private exchangeContractErrCodesToMsg = {
[ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.ORDER_FILL_EXPIRED,
[ExchangeContractErrCodes.ERROR_CANCEL_EXPIRED]: ExchangeContractErrs.ORDER_FILL_EXPIRED,
[ExchangeContractErrCodes.ERROR_FILL_NO_VALUE]: ExchangeContractErrs.ORDER_REMAINING_FILL_AMOUNT_ZERO,
[ExchangeContractErrCodes.ERROR_CANCEL_NO_VALUE]: ExchangeContractErrs.ORDER_REMAINING_FILL_AMOUNT_ZERO,
[ExchangeContractErrCodes.ERROR_FILL_TRUNCATION]: ExchangeContractErrs.ORDER_FILL_ROUNDING_ERROR,
[ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.FILL_BALANCE_ALLOWANCE_ERROR,
};
private exchangeContractIfExists?: ExchangeContract;
constructor(web3Wrapper: Web3Wrapper) {
private tokenWrapper: TokenWrapper;
constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper) {
super(web3Wrapper);
this.tokenWrapper = tokenWrapper;
}
public invalidateContractInstance(): void {
delete this.exchangeContractIfExists;
@@ -20,23 +44,188 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema);
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
const senderAddressIfExists = await this.web3Wrapper.getSenderAddressIfExistsAsync();
assert.assert(!_.isUndefined(senderAddressIfExists), ZeroExError.USER_HAS_NO_ASSOCIATED_ADDRESSES);
const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
const exchangeInstance = await this.getExchangeContractAsync();
const exchangeContract = await this.getExchangeContractAsync();
const isValidSignature = await exchangeContract.isValidSignature.call(
const isValidSignature = await exchangeInstance.isValidSignature.call(
signerAddressHex,
dataHex,
ecSignature.v,
ecSignature.r,
ecSignature.s,
{
from: senderAddressIfExists,
from: senderAddress,
},
);
return isValidSignature;
}
/**
* Fills a signed order with a fillAmount denominated in baseUnits of the taker token.
* Since the order in which transactions are included in the next block is indeterminate, race-conditions
* could arise where a users balance or allowance changes before the fillOrder executes. Because of this,
* we allow you to specify `shouldCheckTransfer`. If true, the smart contract will not throw if while
* executing, the parties do not have sufficient balances/allowances, preserving gas costs. Setting it to
* false forgoes this check and causes the smart contract to throw instead.
*/
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber,
shouldCheckTransfer: boolean): Promise<void> {
assert.doesConformToSchema('signedOrder',
SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object),
signedOrderSchema);
assert.isBigNumber('fillTakerAmount', fillTakerAmount);
assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer);
const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
const exchangeInstance = await this.getExchangeContractAsync();
await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerAmount, senderAddress);
const orderAddresses: OrderAddresses = [
signedOrder.maker,
signedOrder.taker,
signedOrder.makerTokenAddress,
signedOrder.takerTokenAddress,
signedOrder.feeRecipient,
];
const orderValues: OrderValues = [
signedOrder.makerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerFee,
signedOrder.takerFee,
signedOrder.expirationUnixTimestampSec,
signedOrder.salt,
];
const gas = await exchangeInstance.fill.estimateGas(
orderAddresses,
orderValues,
fillTakerAmount,
shouldCheckTransfer,
signedOrder.ecSignature.v,
signedOrder.ecSignature.r,
signedOrder.ecSignature.s,
{
from: senderAddress,
},
);
const response: ContractResponse = await exchangeInstance.fill(
orderAddresses,
orderValues,
fillTakerAmount,
shouldCheckTransfer,
signedOrder.ecSignature.v,
signedOrder.ecSignature.r,
signedOrder.ecSignature.s,
{
from: senderAddress,
gas,
},
);
this.throwErrorLogsAsErrors(response.logs);
}
private async validateFillOrderAndThrowIfInvalidAsync(signedOrder: SignedOrder,
fillTakerAmount: BigNumber.BigNumber,
senderAddress: string): Promise<void> {
if (fillTakerAmount.eq(0)) {
throw new Error(ExchangeContractErrs.ORDER_REMAINING_FILL_AMOUNT_ZERO);
}
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== senderAddress) {
throw new Error(ExchangeContractErrs.TRANSACTION_SENDER_IS_NOT_FILL_ORDER_TAKER);
}
const currentUnixTimestampSec = Date.now() / 1000;
if (signedOrder.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
throw new Error(ExchangeContractErrs.ORDER_FILL_EXPIRED);
}
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
await this.validateFillOrderBalancesAndAllowancesAndThrowIfInvalidAsync(signedOrder, fillTakerAmount,
senderAddress, zrxTokenAddress);
const wouldRoundingErrorOccur = await this.isRoundingErrorAsync(
signedOrder.takerTokenAmount, fillTakerAmount, signedOrder.makerTokenAmount,
);
if (wouldRoundingErrorOccur) {
throw new Error(ExchangeContractErrs.ORDER_FILL_ROUNDING_ERROR);
}
}
/**
* This method does not currently validate the edge-case where the makerToken or takerToken is also the token used
* to pay fees (ZRX). It is possible for them to have enough for fees and the transfer but not both.
* Handling the edge-cases that arise when this happens would require making sure that the user has sufficient
* funds to pay both the fees and the transfer amount. We decided to punt on this for now as the contracts
* will throw for these edge-cases.
* TODO: Throw errors before calling the smart contract for these edge-cases
* TODO: in order to minimize the callers gas costs.
*/
private async validateFillOrderBalancesAndAllowancesAndThrowIfInvalidAsync(signedOrder: SignedOrder,
fillTakerAmount: BigNumber.BigNumber,
senderAddress: string,
zrxTokenAddress: string): Promise<void> {
const makerBalance = await this.tokenWrapper.getBalanceAsync(signedOrder.makerTokenAddress,
signedOrder.maker);
const takerBalance = await this.tokenWrapper.getBalanceAsync(signedOrder.takerTokenAddress, senderAddress);
const makerAllowance = await this.tokenWrapper.getProxyAllowanceAsync(signedOrder.makerTokenAddress,
signedOrder.maker);
const takerAllowance = await this.tokenWrapper.getProxyAllowanceAsync(signedOrder.takerTokenAddress,
senderAddress);
// exchangeRate is the price of one maker token denominated in taker tokens
const exchangeRate = signedOrder.takerTokenAmount.div(signedOrder.makerTokenAmount);
const fillMakerAmountInBaseUnits = fillTakerAmount.div(exchangeRate);
if (fillTakerAmount.greaterThan(takerBalance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_TAKER_BALANCE);
}
if (fillTakerAmount.greaterThan(takerAllowance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_TAKER_ALLOWANCE);
}
if (fillMakerAmountInBaseUnits.greaterThan(makerBalance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_MAKER_BALANCE);
}
if (fillMakerAmountInBaseUnits.greaterThan(makerAllowance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_MAKER_ALLOWANCE);
}
const makerFeeBalance = await this.tokenWrapper.getBalanceAsync(zrxTokenAddress,
signedOrder.maker);
const takerFeeBalance = await this.tokenWrapper.getBalanceAsync(zrxTokenAddress, senderAddress);
const makerFeeAllowance = await this.tokenWrapper.getProxyAllowanceAsync(zrxTokenAddress,
signedOrder.maker);
const takerFeeAllowance = await this.tokenWrapper.getProxyAllowanceAsync(zrxTokenAddress,
senderAddress);
if (signedOrder.takerFee.greaterThan(takerFeeBalance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_TAKER_FEE_BALANCE);
}
if (signedOrder.takerFee.greaterThan(takerFeeAllowance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_TAKER_FEE_ALLOWANCE);
}
if (signedOrder.makerFee.greaterThan(makerFeeBalance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_MAKER_FEE_BALANCE);
}
if (signedOrder.makerFee.greaterThan(makerFeeAllowance)) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_MAKER_FEE_ALLOWANCE);
}
}
private throwErrorLogsAsErrors(logs: ContractEvent[]): void {
const errEvent = _.find(logs, {event: 'LogError'});
if (!_.isUndefined(errEvent)) {
const errCode = errEvent.args.errorId.toNumber();
const errMessage = this.exchangeContractErrCodesToMsg[errCode];
throw new Error(errMessage);
}
}
private async isRoundingErrorAsync(takerTokenAmount: BigNumber.BigNumber,
fillTakerAmount: BigNumber.BigNumber,
makerTokenAmount: BigNumber.BigNumber): Promise<boolean> {
const exchangeInstance = await this.getExchangeContractAsync();
const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
const isRoundingError = await exchangeInstance.isRoundingError.call(
takerTokenAmount, fillTakerAmount, makerTokenAmount, {
from: senderAddress,
},
);
return isRoundingError;
}
private async getExchangeContractAsync(): Promise<ExchangeContract> {
if (!_.isUndefined(this.exchangeContractIfExists)) {
return this.exchangeContractIfExists;
@@ -45,4 +234,8 @@ export class ExchangeWrapper extends ContractWrapper {
this.exchangeContractIfExists = contractInstance as ExchangeContract;
return this.exchangeContractIfExists;
}
private async getZRXTokenAddressAsync(): Promise<string> {
const exchangeInstance = await this.getExchangeContractAsync();
return exchangeInstance.ZRX.call();
}
}

1
src/globals.d.ts vendored
View File

@@ -1,4 +1,5 @@
declare module 'chai-bignumber';
declare module 'dirty-chai';
declare module 'bn.js';
declare module 'request-promise-native';
declare module 'web3-provider-engine';

View File

@@ -0,0 +1,50 @@
export const addressSchema = {
id: '/addressSchema',
type: 'string',
pattern: '^0[xX][0-9A-Fa-f]{40}$',
};
export const numberSchema = {
id: '/numberSchema',
type: 'string',
format: '\d+(\.\d+)?',
};
export const orderSchema = {
id: '/orderSchema',
properties: {
maker: {$ref: '/addressSchema'},
taker: {$ref: '/addressSchema'},
makerFee: {$ref: '/numberSchema'},
takerFee: {$ref: '/numberSchema'},
makerTokenAmount: {$ref: '/numberSchema'},
takerTokenAmount: {$ref: '/numberSchema'},
makerTokenAddress: {$ref: '/addressSchema'},
takerTokenAddress: {$ref: '/addressSchema'},
salt: {$ref: '/numberSchema'},
feeRecipient: {$ref: '/addressSchema'},
expirationUnixTimestampSec: {$ref: '/numberSchema'},
},
required: [
'maker', 'taker', 'makerFee', 'takerFee', 'makerTokenAmount', 'takerTokenAmount',
'salt', 'feeRecipient', 'expirationUnixTimestampSec',
],
type: 'object',
};
export const signedOrderSchema = {
id: '/signedOrderSchema',
allOf: [
{ $ref: '/orderSchema' },
{
properties: {
ecSignature: {$ref: '/ECSignature'},
},
required: ['ecSignature'],
},
],
};

View File

@@ -10,13 +10,14 @@ function strEnum(values: string[]): {[key: string]: string} {
}
export const ZeroExError = strEnum([
'CONTRACT_DOES_NOT_EXIST',
'UNHANDLED_ERROR',
'USER_HAS_NO_ASSOCIATED_ADDRESSES',
'INVALID_SIGNATURE',
'CONTRACT_NOT_DEPLOYED_ON_NETWORK',
'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER',
'INSUFFICIENT_BALANCE_FOR_TRANSFER',
'CONTRACT_DOES_NOT_EXIST',
'UNHANDLED_ERROR',
'USER_HAS_NO_ASSOCIATED_ADDRESSES',
'INVALID_SIGNATURE',
'CONTRACT_NOT_DEPLOYED_ON_NETWORK',
'ZRX_NOT_IN_TOKEN_REGISTRY',
'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER',
'INSUFFICIENT_BALANCE_FOR_TRANSFER',
]);
export type ZeroExError = keyof typeof ZeroExError;
@@ -29,8 +30,26 @@ export interface ECSignature {
s: string;
}
export type OrderAddresses = [string, string, string, string, string];
export type OrderValues = [BigNumber.BigNumber, BigNumber.BigNumber, BigNumber.BigNumber,
BigNumber.BigNumber, BigNumber.BigNumber, BigNumber.BigNumber];
export interface ExchangeContract {
isValidSignature: any;
isRoundingError: {
call: (takerTokenAmount: BigNumber.BigNumber, fillTakerAmount: BigNumber.BigNumber,
makerTokenAmount: BigNumber.BigNumber, txOpts: TxOpts) => Promise<boolean>;
};
fill: {
(orderAddresses: OrderAddresses, orderValues: OrderValues, fillAmount: BigNumber.BigNumber,
shouldCheckTransfer: boolean, v: number, r: string, s: string, txOpts: TxOpts): ContractResponse;
estimateGas: (orderAddresses: OrderAddresses, orderValues: OrderValues, fillAmount: BigNumber.BigNumber,
shouldCheckTransfer: boolean, v: number, r: string, s: string, txOpts: TxOpts) => number;
};
ZRX: {
call: () => Promise<string>;
};
}
export interface TokenContract {
@@ -61,6 +80,60 @@ export const SolidityTypes = strEnum([
]);
export type SolidityTypes = keyof typeof SolidityTypes;
export enum ExchangeContractErrCodes {
ERROR_FILL_EXPIRED, // Order has already expired
ERROR_FILL_NO_VALUE, // Order has already been fully filled or cancelled
ERROR_FILL_TRUNCATION, // Rounding error too large
ERROR_FILL_BALANCE_ALLOWANCE, // Insufficient balance or allowance for token transfer
ERROR_CANCEL_EXPIRED, // Order has already expired
ERROR_CANCEL_NO_VALUE, // Order has already been fully filled or cancelled
}
export const ExchangeContractErrs = strEnum([
'ORDER_FILL_EXPIRED',
'ORDER_REMAINING_FILL_AMOUNT_ZERO',
'ORDER_FILL_ROUNDING_ERROR',
'FILL_BALANCE_ALLOWANCE_ERROR',
'INSUFFICIENT_TAKER_BALANCE',
'INSUFFICIENT_TAKER_ALLOWANCE',
'INSUFFICIENT_MAKER_BALANCE',
'INSUFFICIENT_MAKER_ALLOWANCE',
'INSUFFICIENT_TAKER_FEE_BALANCE',
'INSUFFICIENT_TAKER_FEE_ALLOWANCE',
'INSUFFICIENT_MAKER_FEE_BALANCE',
'INSUFFICIENT_MAKER_FEE_ALLOWANCE',
'TRANSACTION_SENDER_IS_NOT_FILL_ORDER_TAKER',
]);
export type ExchangeContractErrs = keyof typeof ExchangeContractErrs;
export interface ContractResponse {
logs: ContractEvent[];
}
export interface ContractEvent {
event: string;
args: any;
}
export interface Order {
maker: string;
taker: string;
makerFee: BigNumber.BigNumber;
takerFee: BigNumber.BigNumber;
makerTokenAmount: BigNumber.BigNumber;
takerTokenAmount: BigNumber.BigNumber;
makerTokenAddress: string;
takerTokenAddress: string;
salt: BigNumber.BigNumber;
feeRecipient: string;
expirationUnixTimestampSec: BigNumber.BigNumber;
}
export interface SignedOrder extends Order {
ecSignature: ECSignature;
}
// [address, name, symbol, projectUrl, decimals, ipfsHash, swarmHash]
export type TokenMetadata = [string, string, string, string, BigNumber.BigNumber, string, string];

View File

@@ -33,6 +33,9 @@ export const assert = {
isNumber(variableName: string, value: number): void {
this.assert(_.isFinite(value), this.typeAssertionMessage(variableName, 'number', value));
},
isBoolean(variableName: string, value: boolean): void {
this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value));
},
doesConformToSchema(variableName: string, value: object, schema: Schema): void {
const schemaValidator = new SchemaValidator();
const validationResult = schemaValidator.validate(value, schema);

View File

@@ -1,14 +1,26 @@
import {Validator, ValidatorResult} from 'jsonschema';
import {ecSignatureSchema, ecSignatureParameter} from '../schemas/ec_signature_schema';
import {addressSchema, numberSchema, orderSchema, signedOrderSchema} from '../schemas/order_schemas';
import {tokenSchema} from '../schemas/token_schema';
export class SchemaValidator {
private validator: Validator;
// In order to validate a complex JS object using jsonschema, we must replace any complex
// sub-types (e.g BigNumber) with a simpler string representation. Since BigNumber and other
// complex types implement the `toString` method, we can stringify the object and
// then parse it. The resultant object can then be checked using jsonschema.
public static convertToJSONSchemaCompatibleObject(obj: object): object {
return JSON.parse(JSON.stringify(obj));
}
constructor() {
this.validator = new Validator();
this.validator.addSchema(ecSignatureParameter, ecSignatureParameter.id);
this.validator.addSchema(ecSignatureSchema, ecSignatureSchema.id);
this.validator.addSchema(tokenSchema, tokenSchema.id);
this.validator.addSchema(orderSchema, orderSchema.id);
this.validator.addSchema(numberSchema, numberSchema.id);
this.validator.addSchema(addressSchema, addressSchema.id);
this.validator.addSchema(ecSignatureSchema, ecSignatureSchema.id);
this.validator.addSchema(signedOrderSchema, signedOrderSchema.id);
this.validator.addSchema(ecSignatureParameter, ecSignatureParameter.id);
}
public validate(instance: object, schema: Schema): ValidatorResult {
return this.validator.validate(instance, schema);

View File

@@ -2,6 +2,8 @@ import * as _ from 'lodash';
import * as Web3 from 'web3';
import * as BigNumber from 'bignumber.js';
import promisify = require('es6-promisify');
import {ZeroExError} from './types';
import {assert} from './utils/assert';
export class Web3Wrapper {
private web3: Web3;
@@ -15,13 +17,16 @@ export class Web3Wrapper {
public isAddress(address: string): boolean {
return this.web3.isAddress(address);
}
public async getSenderAddressIfExistsAsync(): Promise<string|undefined> {
const defaultAccount = this.web3.eth.defaultAccount;
if (!_.isUndefined(defaultAccount)) {
return defaultAccount;
}
const firstAccount = await this.getFirstAddressIfExistsAsync();
return firstAccount;
public getDefaultAccount(): string {
return this.web3.eth.defaultAccount;
}
public setDefaultAccount(address: string): void {
this.web3.eth.defaultAccount = address;
}
public async getSenderAddressOrThrowAsync(): Promise<string> {
const senderAddressIfExists = await this.getSenderAddressIfExistsAsync();
assert.assert(!_.isUndefined(senderAddressIfExists), ZeroExError.USER_HAS_NO_ASSOCIATED_ADDRESSES);
return senderAddressIfExists as string;
}
public async getFirstAddressIfExistsAsync(): Promise<string|undefined> {
const addresses = await this.getAvailableSenderAddressesAsync();
@@ -68,6 +73,14 @@ export class Web3Wrapper {
const {timestamp} = await promisify(this.web3.eth.getBlock)(blockHash);
return timestamp;
}
public async getSenderAddressIfExistsAsync(): Promise<string|undefined> {
const defaultAccount = this.web3.eth.defaultAccount;
if (!_.isUndefined(defaultAccount)) {
return defaultAccount;
}
const firstAccount = await this.getFirstAddressIfExistsAsync();
return firstAccount;
}
private async getAvailableSenderAddressesAsync(): Promise<string[]> {
const addresses: string[] = await promisify(this.web3.eth.getAccounts)();
return addresses;

View File

@@ -3,13 +3,16 @@ import * as chai from 'chai';
import 'mocha';
import * as BigNumber from 'bignumber.js';
import ChaiBigNumber = require('chai-bignumber');
import * as dirtyChai from 'dirty-chai';
import * as Sinon from 'sinon';
import {ZeroEx} from '../src/0x.js';
import {constants} from './utils/constants';
import {web3Factory} from './utils/web3_factory';
import {Order} from '../src/types';
// Use BigNumber chai add-on
chai.config.includeStack = true;
chai.use(ChaiBigNumber());
chai.use(dirtyChai);
const expect = chai.expect;
describe('ZeroEx library', () => {
@@ -20,8 +23,8 @@ describe('ZeroEx library', () => {
// Instantiate the contract instances with the current provider
await (zeroEx.exchange as any).getExchangeContractAsync();
await (zeroEx.tokenRegistry as any).getTokenRegistryContractAsync();
expect((zeroEx.exchange as any).exchangeContractIfExists).to.not.be.undefined;
expect((zeroEx.tokenRegistry as any).tokenRegistryContractIfExists).to.not.be.undefined;
expect((zeroEx.exchange as any).exchangeContractIfExists).to.not.be.undefined();
expect((zeroEx.tokenRegistry as any).tokenRegistryContractIfExists).to.not.be.undefined();
const newProvider = web3Factory.getRpcProvider();
// Add property to newProvider so that we can differentiate it from old provider
@@ -29,8 +32,8 @@ describe('ZeroEx library', () => {
zeroEx.setProvider(newProvider);
// Check that contractInstances with old provider are removed after provider update
expect((zeroEx.exchange as any).exchangeContractIfExists).to.be.undefined;
expect((zeroEx.tokenRegistry as any).tokenRegistryContractIfExists).to.be.undefined;
expect((zeroEx.exchange as any).exchangeContractIfExists).to.be.undefined();
expect((zeroEx.tokenRegistry as any).tokenRegistryContractIfExists).to.be.undefined();
// Check that all nested web3 instances return the updated provider
const nestedWeb3WrapperProvider = (zeroEx as any).web3Wrapper.getCurrentProvider();
@@ -41,43 +44,6 @@ describe('ZeroEx library', () => {
expect((tokenRegistryWeb3WrapperProvider as any).zeroExTestId).to.be.a('number');
});
});
describe('#getOrderHash', () => {
const expectedOrderHash = '0x103a5e97dab5dbeb8f385636f86a7d1e458a7ccbe1bd194727f0b2f85ab116c7';
it('defaults takerAddress to NULL address', () => {
const orderHash = ZeroEx.getOrderHashHex(
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
'',
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
);
expect(orderHash).to.be.equal(expectedOrderHash);
});
it('calculates the order hash', () => {
const orderHash = ZeroEx.getOrderHashHex(
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
constants.NULL_ADDRESS,
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
new BigNumber(0),
);
expect(orderHash).to.be.equal(expectedOrderHash);
});
});
describe('#isValidSignature', () => {
// This test data was borrowed from the JSON RPC documentation
// Source: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
@@ -127,47 +93,47 @@ describe('ZeroEx library', () => {
});
it('should return false if the data doesn\'t pertain to the signature & address', () => {
const isValid = ZeroEx.isValidSignature('0x0', signature, address);
expect(isValid).to.be.false;
expect(isValid).to.be.false();
});
it('should return false if the address doesn\'t pertain to the signature & data', () => {
const validUnrelatedAddress = '0x8b0292B11a196601eD2ce54B665CaFEca0347D42';
const isValid = ZeroEx.isValidSignature(data, signature, validUnrelatedAddress);
expect(isValid).to.be.false;
expect(isValid).to.be.false();
});
it('should return false if the signature doesn\'t pertain to the data & address', () => {
const wrongSignature = _.assign({}, signature, {v: 28});
const isValid = ZeroEx.isValidSignature(data, wrongSignature, address);
expect(isValid).to.be.false;
expect(isValid).to.be.false();
});
it('should return true if the signature does pertain to the data & address', () => {
const isValid = ZeroEx.isValidSignature(data, signature, address);
expect(isValid).to.be.true;
expect(isValid).to.be.true();
});
});
describe('#generateSalt', () => {
it('generates different salts', () => {
const equal = ZeroEx.generatePseudoRandomSalt().eq(ZeroEx.generatePseudoRandomSalt());
expect(equal).to.be.false;
expect(equal).to.be.false();
});
it('generates salt in range [0..2^256)', () => {
const salt = ZeroEx.generatePseudoRandomSalt();
expect(salt.greaterThanOrEqualTo(0)).to.be.true;
expect(salt.greaterThanOrEqualTo(0)).to.be.true();
const twoPow256 = new BigNumber(2).pow(256);
expect(salt.lessThan(twoPow256)).to.be.true;
expect(salt.lessThan(twoPow256)).to.be.true();
});
});
describe('#isValidOrderHash', () => {
it('returns false if the value is not a hex string', () => {
const isValid = ZeroEx.isValidOrderHash('not a hex');
expect(isValid).to.be.false;
expect(isValid).to.be.false();
});
it('returns false if the length is wrong', () => {
const isValid = ZeroEx.isValidOrderHash('0xdeadbeef');
expect(isValid).to.be.false;
expect(isValid).to.be.false();
});
it('returns true if order hash is correct', () => {
const isValid = ZeroEx.isValidOrderHash('0x' + Array(65).join('0'));
expect(isValid).to.be.true;
expect(isValid).to.be.true();
});
});
describe('#toUnitAmount', () => {
@@ -188,6 +154,41 @@ describe('ZeroEx library', () => {
expect(baseUnitAmount).to.be.bignumber.equal(expectedUnitAmount);
});
});
describe('#getOrderHashAsync', () => {
const exchangeContractAddress = constants.NULL_ADDRESS;
const expectedOrderHash = '0x103a5e97dab5dbeb8f385636f86a7d1e458a7ccbe1bd194727f0b2f85ab116c7';
const order: Order = {
maker: constants.NULL_ADDRESS,
taker: constants.NULL_ADDRESS,
feeRecipient: constants.NULL_ADDRESS,
makerTokenAddress: constants.NULL_ADDRESS,
takerTokenAddress: constants.NULL_ADDRESS,
salt: new BigNumber(0),
makerFee: new BigNumber(0),
takerFee: new BigNumber(0),
makerTokenAmount: new BigNumber(0),
takerTokenAmount: new BigNumber(0),
expirationUnixTimestampSec: new BigNumber(0),
};
let stubs: Sinon.SinonStub[] = [];
afterEach(() => {
// clean up any stubs after the test has completed
_.each(stubs, s => s.restore());
stubs = [];
});
it('calculates the order hash', async () => {
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3);
stubs = [
Sinon.stub((zeroEx as any), 'getExchangeAddressAsync')
.returns(Promise.resolve(exchangeContractAddress)),
];
const orderHash = await zeroEx.getOrderHashHexAsync(order);
expect(orderHash).to.be.equal(expectedOrderHash);
});
});
describe('#signOrderHashAsync', () => {
let stubs: Sinon.SinonStub[] = [];
afterEach(() => {

View File

@@ -1,92 +0,0 @@
import 'mocha';
import * as chai from 'chai';
import {web3Factory} from './utils/web3_factory';
import {ZeroEx} from '../src/0x.js';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle();
describe('ExchangeWrapper', () => {
let zeroEx: ZeroEx;
before(async () => {
const web3 = web3Factory.create();
zeroEx = new ZeroEx(web3);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#isValidSignatureAsync', () => {
// The Exchange smart contract `isValidSignature` method only validates orderHashes and assumes
// the length of the data is exactly 32 bytes. Thus for these tests, we use data of this size.
const dataHex = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
const signature = {
v: 27,
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
};
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
describe('should throw if passed a malformed signature', () => {
it('malformed v', async () => {
const malformedSignature = {
v: 34,
r: signature.r,
s: signature.s,
};
expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
it('r lacks 0x prefix', () => {
const malformedR = signature.r.replace('0x', '');
const malformedSignature = {
v: signature.v,
r: malformedR,
s: signature.s,
};
expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
it('r is too short', () => {
const malformedR = signature.r.substr(10);
const malformedSignature = {
v: signature.v,
r: malformedR,
s: signature.s.replace('0', 'z'),
};
expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
it('s is not hex', () => {
const malformedS = signature.s.replace('0', 'z');
const malformedSignature = {
v: signature.v,
r: signature.r,
s: malformedS,
};
expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected;
});
});
it('should return false if the data doesn\'t pertain to the signature & address', async () => {
const isValid = await zeroEx.exchange.isValidSignatureAsync('0x0', signature, address);
expect(isValid).to.be.false;
});
it('should return false if the address doesn\'t pertain to the signature & dataHex', async () => {
const validUnrelatedAddress = '0x8b0292B11a196601eD2ce54B665CaFEca0347D42';
const isValid = await zeroEx.exchange.isValidSignatureAsync(dataHex, signature, validUnrelatedAddress);
expect(isValid).to.be.false;
});
it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => {
const wrongSignature = Object.assign({}, signature, {v: 28});
const isValid = await zeroEx.exchange.isValidSignatureAsync(dataHex, wrongSignature, address);
expect(isValid).to.be.false;
});
it('should return true if the signature does pertain to the dataHex & address', async () => {
const isValid = await zeroEx.exchange.isValidSignatureAsync(dataHex, signature, address);
expect(isValid).to.be.true;
});
});
});

View File

@@ -0,0 +1,329 @@
import 'mocha';
import * as _ from 'lodash';
import * as chai from 'chai';
import * as Web3 from 'web3';
import * as BigNumber from 'bignumber.js';
import * as dirtyChai from 'dirty-chai';
import ChaiBigNumber = require('chai-bignumber');
import promisify = require('es6-promisify');
import {web3Factory} from './utils/web3_factory';
import {ZeroEx} from '../src/0x.js';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import {ExchangeContractErrs, SignedOrder, Token} from '../src/types';
import {FillScenarios} from './utils/fill_scenarios';
import {TokenUtils} from './utils/token_utils';
chai.config.includeStack = true;
chai.use(dirtyChai);
chai.use(ChaiBigNumber());
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle();
describe('ExchangeWrapper', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let userAddresses: string[];
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3);
userAddresses = await promisify(web3.eth.getAccounts)();
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#isValidSignatureAsync', () => {
// The Exchange smart contract `isValidSignature` method only validates orderHashes and assumes
// the length of the data is exactly 32 bytes. Thus for these tests, we use data of this size.
const dataHex = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
const signature = {
v: 27,
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
};
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
describe('should throw if passed a malformed signature', () => {
it('malformed v', async () => {
const malformedSignature = {
v: 34,
r: signature.r,
s: signature.s,
};
return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected();
});
it('r lacks 0x prefix', async () => {
const malformedR = signature.r.replace('0x', '');
const malformedSignature = {
v: signature.v,
r: malformedR,
s: signature.s,
};
return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected();
});
it('r is too short', async () => {
const malformedR = signature.r.substr(10);
const malformedSignature = {
v: signature.v,
r: malformedR,
s: signature.s.replace('0', 'z'),
};
return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected();
});
it('s is not hex', async () => {
const malformedS = signature.s.replace('0', 'z');
const malformedSignature = {
v: signature.v,
r: signature.r,
s: malformedS,
};
return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address))
.to.be.rejected();
});
});
it('should return false if the data doesn\'t pertain to the signature & address', async () => {
const isValid = await zeroEx.exchange.isValidSignatureAsync('0x0', signature, address);
expect(isValid).to.be.false();
});
it('should return false if the address doesn\'t pertain to the signature & dataHex', async () => {
const validUnrelatedAddress = '0x8b0292B11a196601eD2ce54B665CaFEca0347D42';
const isValid = await zeroEx.exchange.isValidSignatureAsync(dataHex, signature, validUnrelatedAddress);
expect(isValid).to.be.false();
});
it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => {
const wrongSignature = {...signature, v: 28};
const isValid = await zeroEx.exchange.isValidSignatureAsync(dataHex, wrongSignature, address);
expect(isValid).to.be.false();
});
it('should return true if the signature does pertain to the dataHex & address', async () => {
const isValid = await zeroEx.exchange.isValidSignatureAsync(dataHex, signature, address);
expect(isValid).to.be.true();
});
});
describe('#fillOrderAsync', () => {
let tokens: Token[];
let makerTokenAddress: string;
let takerTokenAddress: string;
let fillScenarios: FillScenarios;
let coinbase: string;
let makerAddress: string;
let takerAddress: string;
let feeRecipient: string;
let zrxTokenAddress: string;
const fillTakerAmount = new BigNumber(5);
const shouldCheckTransfer = false;
before(async () => {
[coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
const tokenUtils = new TokenUtils(tokens);
const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress);
});
afterEach('reset default account', () => {
zeroEx.setTransactionSenderAccount(userAddresses[0]);
});
describe('failed fills', () => {
it('should throw when the fill amount is zero', async () => {
const fillableAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const zeroFillAmount = new BigNumber(0);
zeroEx.setTransactionSenderAccount(takerAddress);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, zeroFillAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.ORDER_REMAINING_FILL_AMOUNT_ZERO);
});
it('should throw when sender is not a taker', async () => {
const fillableAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.TRANSACTION_SENDER_IS_NOT_FILL_ORDER_TAKER);
});
it('should throw when order is expired', async () => {
const expirationInPast = new BigNumber(42);
const fillableAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, expirationInPast,
);
zeroEx.setTransactionSenderAccount(takerAddress);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.ORDER_FILL_EXPIRED);
});
describe('should throw when not enough balance or allowance to fulfill the order', () => {
const fillableAmount = new BigNumber(5);
const balanceToSubtractFromMaker = new BigNumber(3);
const lackingAllowance = new BigNumber(3);
let signedOrder: SignedOrder;
beforeEach('create fillable signed order', async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
});
it('should throw when taker balance is less than fill amount', async () => {
await zeroEx.token.transferAsync(
takerTokenAddress, takerAddress, coinbase, balanceToSubtractFromMaker,
);
zeroEx.setTransactionSenderAccount(takerAddress);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_TAKER_BALANCE);
});
it('should throw when taker allowance is less than fill amount', async () => {
const newAllowanceWhichIsLessThanFillAmount = fillTakerAmount.minus(lackingAllowance);
await zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress,
newAllowanceWhichIsLessThanFillAmount);
zeroEx.setTransactionSenderAccount(takerAddress);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_TAKER_ALLOWANCE);
});
it('should throw when maker balance is less than maker fill amount', async () => {
await zeroEx.token.transferAsync(
makerTokenAddress, makerAddress, coinbase, balanceToSubtractFromMaker,
);
zeroEx.setTransactionSenderAccount(takerAddress);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_MAKER_BALANCE);
});
it('should throw when maker allowance is less than maker fill amount', async () => {
const newAllowanceWhichIsLessThanFillAmount = fillTakerAmount.minus(lackingAllowance);
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress,
newAllowanceWhichIsLessThanFillAmount);
zeroEx.setTransactionSenderAccount(takerAddress);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_MAKER_ALLOWANCE);
});
});
it('should throw when there a rounding error would have occurred', async () => {
const makerAmount = new BigNumber(3);
const takerAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
makerAmount, takerAmount,
);
const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
zeroEx.setTransactionSenderAccount(takerAddress);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmountThatCausesRoundingError, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.ORDER_FILL_ROUNDING_ERROR);
});
describe('should throw when not enough balance or allowance to pay fees', () => {
const fillableAmount = new BigNumber(5);
const makerFee = new BigNumber(2);
const takerFee = new BigNumber(2);
let signedOrder: SignedOrder;
beforeEach('setup', async () => {
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
makerAddress, takerAddress, fillableAmount, feeRecipient,
);
zeroEx.setTransactionSenderAccount(takerAddress);
});
it('should throw when maker doesn\'t have enough balance to pay fees', async () => {
const balanceToSubtractFromMaker = new BigNumber(1);
await zeroEx.token.transferAsync(
zrxTokenAddress, makerAddress, coinbase, balanceToSubtractFromMaker,
);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_MAKER_FEE_BALANCE);
});
it('should throw when maker doesn\'t have enough allowance to pay fees', async () => {
const newAllowanceWhichIsLessThanFees = makerFee.minus(1);
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, makerAddress,
newAllowanceWhichIsLessThanFees);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_MAKER_FEE_ALLOWANCE);
});
it('should throw when taker doesn\'t have enough balance to pay fees', async () => {
const balanceToSubtractFromTaker = new BigNumber(1);
await zeroEx.token.transferAsync(
zrxTokenAddress, takerAddress, coinbase, balanceToSubtractFromTaker,
);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_TAKER_FEE_BALANCE);
});
it('should throw when taker doesn\'t have enough allowance to pay fees', async () => {
const newAllowanceWhichIsLessThanFees = makerFee.minus(1);
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, takerAddress,
newAllowanceWhichIsLessThanFees);
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, fillTakerAmount, shouldCheckTransfer,
)).to.be.rejectedWith(ExchangeContractErrs.INSUFFICIENT_TAKER_FEE_ALLOWANCE);
});
});
});
describe('successful fills', () => {
it('should fill a valid order', async () => {
const fillableAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount);
zeroEx.setTransactionSenderAccount(takerAddress);
await zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmount, shouldCheckTransfer);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount.minus(fillTakerAmount));
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillTakerAmount);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillTakerAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount.minus(fillTakerAmount));
});
it('should partially fill the valid order', async () => {
const fillableAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const partialFillAmount = new BigNumber(3);
zeroEx.setTransactionSenderAccount(takerAddress);
await zeroEx.exchange.fillOrderAsync(signedOrder, partialFillAmount, shouldCheckTransfer);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(partialFillAmount);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(partialFillAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
});
it('should fill the valid orders with fees', async () => {
const fillableAmount = new BigNumber(5);
const makerFee = new BigNumber(1);
const takerFee = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
makerAddress, takerAddress, fillableAmount, feeRecipient,
);
zeroEx.setTransactionSenderAccount(takerAddress);
await zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmount, shouldCheckTransfer);
expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient))
.to.be.bignumber.equal(makerFee.plus(takerFee));
});
});
});
});

View File

@@ -10,6 +10,7 @@ import {Token} from '../src/types';
import {SchemaValidator} from '../src/utils/schema_validator';
import {tokenSchema} from '../src/schemas/token_schema';
chai.config.includeStack = true;
const expect = chai.expect;
chai.use(chaiAsPromised);
const blockchainLifecycle = new BlockchainLifecycle();

View File

@@ -8,6 +8,7 @@ import {ZeroEx} from '../src/0x.js';
import {ZeroExError, Token} from '../src/types';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
chai.config.includeStack = true;
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle();

View File

@@ -17,4 +17,4 @@ export class BlockchainLifecycle {
throw new Error(`Snapshot with id #${this.snapshotId} failed to revert`);
}
}
};
}

View File

@@ -0,0 +1,84 @@
import * as BigNumber from 'bignumber.js';
import {ZeroEx} from '../../src/0x.js';
import {Token, SignedOrder} from '../../src/types';
import {orderFactory} from '../utils/order_factory';
import {constants} from './constants';
export class FillScenarios {
private zeroEx: ZeroEx;
private userAddresses: string[];
private tokens: Token[];
private coinbase: string;
private zrxTokenAddress: string;
constructor(zeroEx: ZeroEx, userAddresses: string[], tokens: Token[], zrxTokenAddress: string) {
this.zeroEx = zeroEx;
this.userAddresses = userAddresses;
this.tokens = tokens;
this.coinbase = userAddresses[0];
this.zrxTokenAddress = zrxTokenAddress;
}
public async createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
makerAddress: string, takerAddress: string,
fillableAmount: BigNumber.BigNumber,
expirationUnixTimestampSec?: BigNumber.BigNumber):
Promise<SignedOrder> {
return this.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
fillableAmount, fillableAmount, expirationUnixTimestampSec,
);
}
public async createFillableSignedOrderWithFeesAsync(
makerTokenAddress: string, takerTokenAddress: string,
makerFee: BigNumber.BigNumber, takerFee: BigNumber.BigNumber,
makerAddress: string, takerAddress: string,
fillableAmount: BigNumber.BigNumber,
feeRecepient: string, expirationUnixTimestampSec?: BigNumber.BigNumber,
): Promise<SignedOrder> {
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
);
}
public async createAsymmetricFillableSignedOrderAsync(
makerTokenAddress: string, takerTokenAddress: string, makerAddress: string, takerAddress: string,
makerFillableAmount: BigNumber.BigNumber, takerFillableAmount: BigNumber.BigNumber,
expirationUnixTimestampSec?: BigNumber.BigNumber): Promise<SignedOrder> {
const makerFee = new BigNumber(0);
const takerFee = new BigNumber(0);
const feeRecepient = constants.NULL_ADDRESS;
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
);
}
private async createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress: string, takerTokenAddress: string,
makerFee: BigNumber.BigNumber, takerFee: BigNumber.BigNumber,
makerAddress: string, takerAddress: string,
makerFillableAmount: BigNumber.BigNumber, takerFillableAmount: BigNumber.BigNumber,
feeRecepient: string, expirationUnixTimestampSec?: BigNumber.BigNumber): Promise<SignedOrder> {
await this.zeroEx.token.transferAsync(makerTokenAddress, this.coinbase, makerAddress, makerFillableAmount);
await this.zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount);
await this.zeroEx.token.transferAsync(takerTokenAddress, this.coinbase, takerAddress, takerFillableAmount);
await this.zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount);
if (!makerFee.isZero()) {
await this.zeroEx.token.transferAsync(this.zrxTokenAddress, this.coinbase, makerAddress, makerFee);
await this.zeroEx.token.setProxyAllowanceAsync(this.zrxTokenAddress, makerAddress, makerFee);
}
if (!takerFee.isZero()) {
await this.zeroEx.token.transferAsync(this.zrxTokenAddress, this.coinbase, takerAddress, takerFee);
await this.zeroEx.token.setProxyAllowanceAsync(this.zrxTokenAddress, takerAddress, takerFee);
}
const prevTransactionSenderAccount = await this.zeroEx.getTransactionSenderAccountIfExistsAsync();
this.zeroEx.setTransactionSenderAccount(makerAddress);
const signedOrder = await orderFactory.createSignedOrderAsync(this.zeroEx,
makerAddress, takerAddress, makerFee, takerFee,
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
feeRecepient, expirationUnixTimestampSec);
// We re-set the transactionSender to avoid introducing side-effects
this.zeroEx.setTransactionSenderAccount(prevTransactionSenderAccount as string);
return signedOrder;
}
}

View File

@@ -0,0 +1,43 @@
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
import {SignedOrder, Token} from '../../src/types';
import {ZeroEx} from '../../src/0x.js';
import {constants} from './constants';
import * as ExchangeArtifacts from '../../src/artifacts/Exchange.json';
export const orderFactory = {
async createSignedOrderAsync(
zeroEx: ZeroEx,
maker: string,
taker: string,
makerFee: BigNumber.BigNumber,
takerFee: BigNumber.BigNumber,
makerTokenAmount: BigNumber.BigNumber,
makerTokenAddress: string,
takerTokenAmount: BigNumber.BigNumber,
takerTokenAddress: string,
feeRecipient: string,
expirationUnixTimestampSec?: BigNumber.BigNumber): Promise<SignedOrder> {
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSec) ?
defaultExpirationUnixTimestampSec :
expirationUnixTimestampSec;
const order = {
maker,
taker,
makerFee,
takerFee,
makerTokenAmount,
takerTokenAmount,
makerTokenAddress,
takerTokenAddress,
salt: ZeroEx.generatePseudoRandomSalt(),
feeRecipient,
expirationUnixTimestampSec,
};
const orderHash = await zeroEx.getOrderHashHexAsync(order);
const ecSignature = await zeroEx.signOrderHashAsync(orderHash);
const signedOrder: SignedOrder = _.assign(order, {ecSignature});
return signedOrder;
},
};

24
test/utils/token_utils.ts Normal file
View File

@@ -0,0 +1,24 @@
import * as _ from 'lodash';
import {Token, ZeroExError} from '../../src/types';
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
export class TokenUtils {
private tokens: Token[];
constructor(tokens: Token[]) {
this.tokens = tokens;
}
public getProtocolTokenOrThrow(): Token {
const zrxToken = _.find(this.tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
if (_.isUndefined(zrxToken)) {
throw new Error(ZeroExError.ZRX_NOT_IN_TOKEN_REGISTRY);
}
return zrxToken;
}
public getNonProtocolTokens(): Token[] {
const nonProtocolTokens = _.filter(this.tokens, token => {
return token.symbol !== PROTOCOL_TOKEN_SYMBOL;
});
return nonProtocolTokens;
}
}

View File

@@ -12,6 +12,8 @@
"include": [
"./src/**/*",
"./test/**/*",
"./node_modules/web3-typescript-typings/index.d.ts"
"./node_modules/web3-typescript-typings/index.d.ts",
"./node_modules/chai-typescript-typings/index.d.ts",
"./node_modules/chai-as-promised-typescript-typings/index.d.ts"
]
}

435
yarn.lock
View File

@@ -6,16 +6,6 @@
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-4.0.2.tgz#22a16946c9faa9f2c9c0ad4c7c3734a3033320ae"
"@types/chai-as-promised@0.0.30":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-0.0.30.tgz#2341321cc796c6c3544a949a063e7609a222f303"
dependencies:
"@types/chai" "*"
"@types/chai@*", "@types/chai@^3.5.2":
version "3.5.2"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.5.2.tgz#c11cd2817d3a401b7ba0f5a420f35c56139b1c1e"
"@types/fs-extra@^3.0.0":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-3.0.2.tgz#00cbf48563f377f9ce5cf24237b21b3d9779e055"
@@ -53,8 +43,8 @@
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.41.tgz#e27cf0817153eb9f2713b2d3f6c68f1e1c3ca608"
"@types/node@*", "@types/node@^7.0.22":
version "7.0.22"
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.22.tgz#4593f4d828bdd612929478ea40c67b4f403ca255"
version "7.0.23"
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.23.tgz#ededfd92e61046c32fcad56ea7e1101733fad4a4"
"@types/shelljs@^0.7.0":
version "0.7.1"
@@ -235,7 +225,7 @@ async@^1.4.0, async@^1.4.2, async@^1.5.2, async@~1.5.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@^2.0.1, async@^2.1.2, async@^2.4.0:
async@^2.1.2, async@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
dependencies:
@@ -310,6 +300,74 @@ babel-generator@^6.18.0, babel-generator@^6.24.1:
source-map "^0.5.0"
trim-right "^1.0.1"
babel-helper-call-delegate@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
dependencies:
babel-helper-hoist-variables "^6.24.1"
babel-runtime "^6.22.0"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-helper-define-map@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080"
dependencies:
babel-helper-function-name "^6.24.1"
babel-runtime "^6.22.0"
babel-types "^6.24.1"
lodash "^4.2.0"
babel-helper-function-name@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
dependencies:
babel-helper-get-function-arity "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-helper-get-function-arity@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-helper-hoist-variables@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-helper-optimise-call-expression@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-helper-regex@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
lodash "^4.2.0"
babel-helper-replace-supers@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
dependencies:
babel-helper-optimise-call-expression "^6.24.1"
babel-messages "^6.23.0"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-helpers@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
@@ -323,6 +381,222 @@ babel-messages@^6.23.0:
dependencies:
babel-runtime "^6.22.0"
babel-plugin-check-es2015-constants@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-arrow-functions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-block-scoping@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576"
dependencies:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
lodash "^4.2.0"
babel-plugin-transform-es2015-classes@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
dependencies:
babel-helper-define-map "^6.24.1"
babel-helper-function-name "^6.24.1"
babel-helper-optimise-call-expression "^6.24.1"
babel-helper-replace-supers "^6.24.1"
babel-messages "^6.23.0"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-plugin-transform-es2015-computed-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
dependencies:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-destructuring@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-duplicate-keys@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-for-of@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-function-name@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b"
dependencies:
babel-helper-function-name "^6.24.1"
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-literals@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-modules-amd@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
dependencies:
babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe"
dependencies:
babel-plugin-transform-strict-mode "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-types "^6.24.1"
babel-plugin-transform-es2015-modules-systemjs@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
dependencies:
babel-helper-hoist-variables "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-modules-umd@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
dependencies:
babel-plugin-transform-es2015-modules-amd "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-object-super@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
dependencies:
babel-helper-replace-supers "^6.24.1"
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-parameters@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
dependencies:
babel-helper-call-delegate "^6.24.1"
babel-helper-get-function-arity "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-plugin-transform-es2015-shorthand-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-spread@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-sticky-regex@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc"
dependencies:
babel-helper-regex "^6.24.1"
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-template-literals@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-typeof-symbol@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-unicode-regex@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9"
dependencies:
babel-helper-regex "^6.24.1"
babel-runtime "^6.22.0"
regexpu-core "^2.0.0"
babel-plugin-transform-regenerator@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418"
dependencies:
regenerator-transform "0.9.11"
babel-plugin-transform-strict-mode@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-preset-es2015@^6.24.0:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939"
dependencies:
babel-plugin-check-es2015-constants "^6.22.0"
babel-plugin-transform-es2015-arrow-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoping "^6.24.1"
babel-plugin-transform-es2015-classes "^6.24.1"
babel-plugin-transform-es2015-computed-properties "^6.24.1"
babel-plugin-transform-es2015-destructuring "^6.22.0"
babel-plugin-transform-es2015-duplicate-keys "^6.24.1"
babel-plugin-transform-es2015-for-of "^6.22.0"
babel-plugin-transform-es2015-function-name "^6.24.1"
babel-plugin-transform-es2015-literals "^6.22.0"
babel-plugin-transform-es2015-modules-amd "^6.24.1"
babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
babel-plugin-transform-es2015-modules-systemjs "^6.24.1"
babel-plugin-transform-es2015-modules-umd "^6.24.1"
babel-plugin-transform-es2015-object-super "^6.24.1"
babel-plugin-transform-es2015-parameters "^6.24.1"
babel-plugin-transform-es2015-shorthand-properties "^6.24.1"
babel-plugin-transform-es2015-spread "^6.22.0"
babel-plugin-transform-es2015-sticky-regex "^6.24.1"
babel-plugin-transform-es2015-template-literals "^6.22.0"
babel-plugin-transform-es2015-typeof-symbol "^6.22.0"
babel-plugin-transform-es2015-unicode-regex "^6.24.1"
babel-plugin-transform-regenerator "^6.24.1"
babel-register@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f"
@@ -335,7 +609,7 @@ babel-register@^6.24.1:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
babel-runtime@^6.22.0:
babel-runtime@^6.18.0, babel-runtime@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
dependencies:
@@ -366,7 +640,7 @@ babel-traverse@^6.18.0, babel-traverse@^6.24.1:
invariant "^2.2.0"
lodash "^4.2.0"
babel-types@^6.18.0, babel-types@^6.24.1:
babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975"
dependencies:
@@ -383,8 +657,8 @@ babelify@^7.3.0:
object-assign "^4.0.0"
babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
version "6.17.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.1.tgz#17f14fddf361b695981fe679385e4f1c01ebd86f"
version "6.17.2"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.2.tgz#201d25ef5f892c41bae49488b08db0dd476e9f5c"
balanced-match@^0.4.1:
version "0.4.2"
@@ -412,9 +686,9 @@ bignumber.js@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.0.2.tgz#2d1dc37ee5968867ecea90b6da4d16e68608d21d"
"bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", "bignumber.js@git+https://github.com/debris/bignumber.js.git#master":
"bignumber.js@git+https://github.com/debris/bignumber.js#master", "bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2":
version "2.0.7"
resolved "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2"
resolved "git+https://github.com/debris/bignumber.js#94d7146671b9719e00a09c29b01a691bc85048c2"
bignumber.js@~2.1.4:
version "2.1.4"
@@ -624,6 +898,12 @@ center-align@^0.1.1:
align-text "^0.1.3"
lazy-cache "^1.0.3"
chai-as-promised-typescript-typings@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/chai-as-promised-typescript-typings/-/chai-as-promised-typescript-typings-0.0.2.tgz#5df99c418917a78eb314e5f83f306cb95ae846cb"
dependencies:
chai-typescript-typings "^0.0.0"
chai-as-promised@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6"
@@ -634,6 +914,10 @@ chai-bignumber@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chai-bignumber/-/chai-bignumber-2.0.0.tgz#0cbf9b81790801c3f24fb77f59fa1e17a9c6e3f2"
chai-typescript-typings@^0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/chai-typescript-typings/-/chai-typescript-typings-0.0.0.tgz#52e076d72cf29129c94ab1dba6e33ce3828a0724"
chai@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247"
@@ -732,7 +1016,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5:
dependencies:
delayed-stream "~1.0.0"
commander@2.9.0:
commander@2.9.0, commander@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
dependencies:
@@ -964,6 +1248,10 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
dirty-chai@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/dirty-chai/-/dirty-chai-1.2.2.tgz#78495e619635f7fe44219aa4c837849bf183142e"
dom-walk@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
@@ -1124,17 +1412,7 @@ ethereumjs-account@^2.0.3, ethereumjs-account@~2.0.4:
ethereumjs-util "^4.0.1"
rlp "^2.0.0"
ethereumjs-block@^1.2.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.5.0.tgz#b0b9018e9cd73146c601dc7db2f6b2a4561e468c"
dependencies:
async "^2.0.1"
ethereum-common "0.0.18"
ethereumjs-tx "^1.2.2"
ethereumjs-util "^5.0.0"
merkle-patricia-tree "^2.1.2"
ethereumjs-block@~1.2.2:
ethereumjs-block@^1.2.2, ethereumjs-block@~1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.2.2.tgz#2ec7534a59021b8ec9b83c30e49690c6ebaedda1"
dependencies:
@@ -1167,7 +1445,7 @@ ethereumjs-testrpc@3.0.5:
web3-provider-engine "~8.1.0"
yargs "~3.29.0"
ethereumjs-tx@^1.0.0, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.0:
ethereumjs-tx@^1.0.0, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.1.tgz#d6909abcfb37da6404fc18124d351eda20047dac"
dependencies:
@@ -1185,9 +1463,11 @@ ethereumjs-util@^4.0.0, ethereumjs-util@^4.0.1, ethereumjs-util@^4.3.0, ethereum
secp256k1 "^3.0.1"
ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.1.1.tgz#122fb38dea747dc62b3aebfc365d1bd48be4b73e"
version "5.1.2"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.1.2.tgz#25ba0215cbb4c2f0b108a6f96af2a2e62e45921f"
dependencies:
babel-preset-es2015 "^6.24.0"
babelify "^7.3.0"
bn.js "^4.8.0"
create-hash "^1.1.2"
ethjs-util "^0.1.3"
@@ -1610,8 +1890,8 @@ heap@~0.2.6:
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac"
highlight.js@^9.0.0:
version "9.11.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.11.0.tgz#47f98c7399918700db2caf230ded12cec41a84ae"
version "9.12.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
hmac-drbg@^1.0.0:
version "1.0.1"
@@ -1921,6 +2201,10 @@ jsesc@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
jsesc@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
json-loader@^0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
@@ -2372,8 +2656,8 @@ native-promise-only@^0.8.1:
resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11"
node-abi@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.0.2.tgz#00f3e0a58100eb480133b48c99a32cc1f9e6c93e"
version "2.0.3"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.0.3.tgz#0ca67e5e667b8e1343549ca17153a815d0bbfdaa"
node-fetch@^1.0.1, node-fetch@~1.6.0:
version "1.6.3"
@@ -2411,8 +2695,8 @@ node-libs-browser@^2.0.0:
vm-browserify "0.0.4"
node-pre-gyp@^0.6.29:
version "0.6.34"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7"
version "0.6.36"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
dependencies:
mkdirp "^0.5.1"
nopt "^4.0.1"
@@ -2571,7 +2855,7 @@ opn@^4.0.0:
object-assign "^4.0.1"
pinkie-promise "^2.0.0"
optimist@^0.6.1, optimist@~0.6.0:
optimist@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
dependencies:
@@ -2908,10 +3192,22 @@ redent@^1.0.0:
indent-string "^2.1.0"
strip-indent "^1.0.1"
regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
regenerator-runtime@^0.10.0:
version "0.10.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
regenerator-transform@0.9.11:
version "0.9.11"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283"
dependencies:
babel-runtime "^6.18.0"
babel-types "^6.19.0"
private "^0.1.6"
regex-cache@^0.4.2:
version "0.4.3"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
@@ -2919,6 +3215,24 @@ regex-cache@^0.4.2:
is-equal-shallow "^0.1.3"
is-primitive "^2.0.0"
regexpu-core@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240"
dependencies:
regenerate "^1.2.1"
regjsgen "^0.2.0"
regjsparser "^0.1.4"
regjsgen@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
regjsparser@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
dependencies:
jsesc "~0.5.0"
remove-trailing-separator@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
@@ -3199,7 +3513,7 @@ sntp@1.x.x:
dependencies:
hoek "2.x.x"
solc@0.4.6:
solc@0.4.6, solc@^0.4.2:
version "0.4.6"
resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.6.tgz#afa929a1ceafc0252cfbb4217c8e2b1dab139db7"
dependencies:
@@ -3208,16 +3522,6 @@ solc@0.4.6:
require-from-string "^1.1.0"
yargs "^4.7.1"
solc@^0.4.2:
version "0.4.11"
resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.11.tgz#2522eb43e7c0419bac2060b96e20a2593bfb5e8b"
dependencies:
fs-extra "^0.30.0"
memorystream "^0.3.1"
require-from-string "^1.1.0"
semver "^5.3.0"
yargs "^4.7.1"
source-list-map@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
@@ -3541,7 +3845,7 @@ truffle-contract@^2.0.0:
truffle-contract-schema "0.0.5"
web3 "^0.18.0"
tslib@^1.6.0:
tslib@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec"
@@ -3556,22 +3860,22 @@ tslint-react@^3.0.0:
resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-3.0.0.tgz#00c48ab7f22e91533b62bdef2c162b49447af00a"
tslint@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.3.2.tgz#e56459fb095a7307f103b84052174f5e3bbef6ed"
version "5.4.0"
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.4.0.tgz#e5e26524ca39fe950a51416456c2f296ccb69348"
dependencies:
babel-code-frame "^6.22.0"
colors "^1.1.2"
commander "^2.9.0"
diff "^3.2.0"
glob "^7.1.1"
optimist "~0.6.0"
resolve "^1.3.2"
semver "^5.3.0"
tslib "^1.6.0"
tsutils "^2.0.0"
tslib "^1.7.1"
tsutils "^2.3.0"
tsutils@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.2.0.tgz#218614657f21c677e4536b4ba75daf8ebce1b367"
tsutils@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.3.0.tgz#96e661d7c2363f31adc8992ac67bbe7b7fc175e5"
tty-browserify@0.0.0:
version "0.0.0"
@@ -3634,8 +3938,8 @@ typescript@2.3.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.2.tgz#f0f045e196f69a72f06b25fd3bd39d01c3ce9984"
typescript@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.3.tgz#9639f3c3b40148e8ca97fe08a51dd1891bb6be22"
version "2.3.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.4.tgz#3d38321828231e434f287514959c37a82b629f42"
uglify-js@^2.6, uglify-js@^2.8.27:
version "2.8.27"
@@ -3723,8 +4027,8 @@ watchpack@^1.3.1:
graceful-fs "^4.1.2"
web3-provider-engine@^12.1.0:
version "12.1.0"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-12.1.0.tgz#92319bb22388aa9ef93254767ea06565867f3a9f"
version "12.2.1"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-12.2.1.tgz#848c2ee187f9701b0a382e2207c9b10f174a8d72"
dependencies:
async "^2.1.2"
clone "^2.0.0"
@@ -3736,6 +4040,7 @@ web3-provider-engine@^12.1.0:
ethereumjs-vm "^2.0.2"
fetch-ponyfill "^4.0.0"
json-rpc-error "^2.0.0"
json-stable-stringify "^1.0.1"
promise-to-callback "^1.0.0"
readable-stream "^2.2.9"
request "^2.67.0"