Merge branch 'master' into remainingTokenMethods
# Conflicts: # src/types.ts # src/web3_wrapper.ts
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
124
src/0x.js.ts
124
src/0x.js.ts
@@ -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
11
src/bignumber_config.ts
Normal 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,
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -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
1
src/globals.d.ts
vendored
@@ -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';
|
||||
|
||||
50
src/schemas/order_schemas.ts
Normal file
50
src/schemas/order_schemas.ts
Normal 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'],
|
||||
},
|
||||
],
|
||||
};
|
||||
87
src/types.ts
87
src/types.ts
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
329
test/exchange_wrapper_test.ts
Normal file
329
test/exchange_wrapper_test.ts
Normal 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));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -17,4 +17,4 @@ export class BlockchainLifecycle {
|
||||
throw new Error(`Snapshot with id #${this.snapshotId} failed to revert`);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
84
test/utils/fill_scenarios.ts
Normal file
84
test/utils/fill_scenarios.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
43
test/utils/order_factory.ts
Normal file
43
test/utils/order_factory.ts
Normal 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
24
test/utils/token_utils.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
435
yarn.lock
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user