From 59f48d6d5702210acea868c3ac2ede6315f0c8ec Mon Sep 17 00:00:00 2001 From: David Sun Date: Mon, 4 Feb 2019 11:19:18 -0500 Subject: [PATCH 01/39] working on big number coercion function --- packages/instant/src/index.umd.ts | 7 ++++++ .../instant/src/util/signed_order_coercion.ts | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 packages/instant/src/util/signed_order_coercion.ts diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 0acf3f2ad1..0c2ce5ec19 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -19,6 +19,7 @@ import { analytics } from './util/analytics'; import { assert } from './util/assert'; import { providerFactory } from './util/provider_factory'; import { util } from './util/util'; +import { coerceSignedOrderBigNumberOfString } from './util/signed_order_coercion' const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); @@ -94,6 +95,12 @@ export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { validateInstantRenderConfig(config, selector); + + // TODO(David Sun) test functionality of order bignumber version coercion + if (!_.isString(config.orderSource)) { + config.orderSource = config.orderSource.map(coerceSignedOrderBigNumberOfString); + } + if (config.shouldDisablePushToHistory) { if (!isInstantRendered()) { renderInstant(config, selector); diff --git a/packages/instant/src/util/signed_order_coercion.ts b/packages/instant/src/util/signed_order_coercion.ts new file mode 100644 index 0000000000..649596a3dd --- /dev/null +++ b/packages/instant/src/util/signed_order_coercion.ts @@ -0,0 +1,25 @@ +import { BigNumber } from '@0x/asset-buyer'; +import { SignedOrder } from '@0x/types'; + +export const coerceBigNumberOrString = (value: any): BigNumber => { + if (typeof value === 'string') { + return new BigNumber(value); + } + if (BigNumber.isBigNumber(value)) { + return new BigNumber(value.toString()); + } + return value; +}; + +// function implies that the signed order already has been invalidated +export const coerceSignedOrderBigNumberOfString = (order: SignedOrder): SignedOrder => { + return { + ...order, + makerFee: coerceBigNumberOrString(order.makerFee), + takerFee: coerceBigNumberOrString(order.takerFee), + makerAssetAmount: coerceBigNumberOrString(order.makerAssetAmount), + takerAssetAmount: coerceBigNumberOrString(order.takerAssetAmount), + salt: coerceBigNumberOrString(order.salt), + expirationTimeSeconds: coerceBigNumberOrString(order.expirationTimeSeconds), + }; +}; From 8de955f3d891620c90c668b4ac0b046e772d4da8 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 5 Feb 2019 21:34:29 +0000 Subject: [PATCH 02/39] Add Heap and Google analytics to Dev Tools Pages --- packages/dev-tools-pages/assets/index.html | 76 ++++++++++++++++++---- packages/dev-tools-pages/pages.js | 8 +++ 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/packages/dev-tools-pages/assets/index.html b/packages/dev-tools-pages/assets/index.html index 5ab1a45f11..73797b9588 100644 --- a/packages/dev-tools-pages/assets/index.html +++ b/packages/dev-tools-pages/assets/index.html @@ -1,14 +1,66 @@ - - - - - - - <%= htmlWebpackPlugin.options.title %> - - -
- - \ No newline at end of file + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + + + + + +
+ + diff --git a/packages/dev-tools-pages/pages.js b/packages/dev-tools-pages/pages.js index 488c2ecd78..62a0226038 100644 --- a/packages/dev-tools-pages/pages.js +++ b/packages/dev-tools-pages/pages.js @@ -15,6 +15,8 @@ const pages = [ 'twitter:site': '@0xproject', 'twitter:image': '/images/og-compiler.png', }, + googleAnalyticsId: 'UA-98720122-4', + heapAnalyticsId: '3772819976', }, { title: 'sol-coverage', @@ -32,6 +34,8 @@ const pages = [ 'twitter:site': '@0xproject', 'twitter:image': '/images/og-cov.png', }, + googleAnalyticsId: 'UA-98720122-3', + heapAnalyticsId: '3386971671', }, { title: 'sol-profiler', @@ -49,6 +53,8 @@ const pages = [ 'twitter:site': '@0xproject', 'twitter:image': '/images/og-profiler.png', }, + googleAnalyticsId: 'UA-98720122-5', + heapAnalyticsId: '3776009943', }, { title: 'sol-trace', @@ -66,6 +72,8 @@ const pages = [ 'twitter:site': '@0xproject', 'twitter:image': '/images/og-trace.png', }, + googleAnalyticsId: 'UA-98720122-6', + heapAnalyticsId: '4172106583', }, ]; From d95af455f1102dc7aa833ebb7b84498cce564df3 Mon Sep 17 00:00:00 2001 From: David Sun Date: Tue, 5 Feb 2019 16:46:51 -0500 Subject: [PATCH 03/39] added coercion util functions --- packages/instant/src/index.umd.ts | 9 +- packages/instant/src/util/maybe_big_number.ts | 11 + .../instant/src/util/signed_order_coercion.ts | 41 +- .../test/util/dependencies/prevbignumber.d.ts | 1772 +++++++++++ .../test/util/dependencies/prevbignumber.js | 2705 +++++++++++++++++ .../test/util/maybe_big_number.test.ts | 71 + 6 files changed, 4584 insertions(+), 25 deletions(-) create mode 100644 packages/instant/test/util/dependencies/prevbignumber.d.ts create mode 100644 packages/instant/test/util/dependencies/prevbignumber.js create mode 100644 packages/instant/test/util/maybe_big_number.test.ts diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 0c2ce5ec19..45913aa47e 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -18,8 +18,8 @@ import { Network, OrderSource } from './types'; import { analytics } from './util/analytics'; import { assert } from './util/assert'; import { providerFactory } from './util/provider_factory'; +import { signedOrderCoercionUtil } from './util/signed_order_coercion'; import { util } from './util/util'; -import { coerceSignedOrderBigNumberOfString } from './util/signed_order_coercion' const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); @@ -94,13 +94,12 @@ export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { } export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { - validateInstantRenderConfig(config, selector); - - // TODO(David Sun) test functionality of order bignumber version coercion if (!_.isString(config.orderSource)) { - config.orderSource = config.orderSource.map(coerceSignedOrderBigNumberOfString); + config.orderSource = config.orderSource.map(signedOrderCoercionUtil.bigNumberCoercion); } + validateInstantRenderConfig(config, selector); + if (config.shouldDisablePushToHistory) { if (!isInstantRendered()) { renderInstant(config, selector); diff --git a/packages/instant/src/util/maybe_big_number.ts b/packages/instant/src/util/maybe_big_number.ts index f48473389d..7e206a1253 100644 --- a/packages/instant/src/util/maybe_big_number.ts +++ b/packages/instant/src/util/maybe_big_number.ts @@ -16,6 +16,17 @@ export const maybeBigNumberUtil = { return validBigNumber.isNaN() ? undefined : validBigNumber; }, + // converts a BigNumber or String to the BigNumber used by 0x libraries + bigNumberOrStringToMaybeBigNumber: (value: any): Maybe => { + if (_.isString(value)) { + return maybeBigNumberUtil.stringToMaybeBigNumber(value); + } + // checks for pre v8 bignumber with member variable + if (BigNumber.isBigNumber(value) || value.isBigNumber) { + return new BigNumber(value.toString()); + } + return undefined; + }, areMaybeBigNumbersEqual: (val1: Maybe, val2: Maybe): boolean => { if (!_.isUndefined(val1) && !_.isUndefined(val2)) { return val1.isEqualTo(val2); diff --git a/packages/instant/src/util/signed_order_coercion.ts b/packages/instant/src/util/signed_order_coercion.ts index 649596a3dd..4209e05e11 100644 --- a/packages/instant/src/util/signed_order_coercion.ts +++ b/packages/instant/src/util/signed_order_coercion.ts @@ -1,25 +1,26 @@ -import { BigNumber } from '@0x/asset-buyer'; import { SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import * as _ from 'lodash'; -export const coerceBigNumberOrString = (value: any): BigNumber => { - if (typeof value === 'string') { - return new BigNumber(value); - } - if (BigNumber.isBigNumber(value)) { - return new BigNumber(value.toString()); - } - return value; +import { maybeBigNumberUtil } from './maybe_big_number'; + +const coerceBigNumberOrString = (value: any): BigNumber => { + const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(value); + return !!bn ? bn : value; }; -// function implies that the signed order already has been invalidated -export const coerceSignedOrderBigNumberOfString = (order: SignedOrder): SignedOrder => { - return { - ...order, - makerFee: coerceBigNumberOrString(order.makerFee), - takerFee: coerceBigNumberOrString(order.takerFee), - makerAssetAmount: coerceBigNumberOrString(order.makerAssetAmount), - takerAssetAmount: coerceBigNumberOrString(order.takerAssetAmount), - salt: coerceBigNumberOrString(order.salt), - expirationTimeSeconds: coerceBigNumberOrString(order.expirationTimeSeconds), - }; +// function implies that the signed order already has been validated +export const signedOrderCoercionUtil = { + // coerces order big number values to the BigNumber version utilized by 0x + bigNumberCoercion: (order: SignedOrder): SignedOrder => { + return { + ...order, + makerFee: coerceBigNumberOrString(order.makerFee), + takerFee: coerceBigNumberOrString(order.takerFee), + makerAssetAmount: coerceBigNumberOrString(order.makerAssetAmount), + takerAssetAmount: coerceBigNumberOrString(order.takerAssetAmount), + salt: coerceBigNumberOrString(order.salt), + expirationTimeSeconds: coerceBigNumberOrString(order.expirationTimeSeconds), + }; + }, }; diff --git a/packages/instant/test/util/dependencies/prevbignumber.d.ts b/packages/instant/test/util/dependencies/prevbignumber.d.ts new file mode 100644 index 0000000000..9b802ec3e1 --- /dev/null +++ b/packages/instant/test/util/dependencies/prevbignumber.d.ts @@ -0,0 +1,1772 @@ +// Type definitions for bignumber.js >=6.0.0 +// Project: https://github.com/MikeMcl/bignumber.js +// Definitions by: Michael Mclaughlin +// Definitions: https://github.com/MikeMcl/bignumber.js + +// Documentation: http://mikemcl.github.io/bignumber.js/ +// +// Exports (available globally or when using import): +// +// class BigNumber (default export) +// type BigNumber.Constructor +// type BigNumber.Instance +// type BigNumber.ModuloMode +// type BigNumber.RoundingMOde +// type BigNumber.Value +// interface BigNumber.Config +// interface BigNumber.Format +// +// Example (alternative syntax commented-out): +// +// import {BigNumber} from "bignumber.js" +// //import BigNumber from "bignumber.js" +// +// let rm: BigNumber.RoundingMode = BigNumber.ROUND_UP; +// let f: BigNumber.Format = { decimalSeparator: ',' }; +// let c: BigNumber.Config = { DECIMAL_PLACES: 4, ROUNDING_MODE: rm, FORMAT: f }; +// BigNumber.config(c); +// +// let v: BigNumber.Value = '12345.6789'; +// let b: BigNumber = new BigNumber(v); +// //let b: BigNumber.Instance = new BigNumber(v); +// +// The use of compiler option `--strictNullChecks` is recommended. + + +type BigNumberConstructor = typeof BigNumber; +type BigNumberInstance = BigNumber; +type BigNumberModuloMode = BigNumberRoundingMode | 9; +type BigNumberRoundingMode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; +type BigNumberValue = string | number | BigNumber; + +/** + * See `BigNumber.config` and `BigNumber.clone`. + */ +interface BigNumberConfig { + + /** + * An integer, 0 to 1e+9. Default value: 20. + * + * The maximum number of decimal places of the result of operations involving division, i.e. + * division, square root and base conversion operations, and exponentiation when the exponent is + * negative. + * + * ```ts + * BigNumber.config({ DECIMAL_PLACES: 5 }) + * BigNumber.set({ DECIMAL_PLACES: 5 }) + * ``` + */ + DECIMAL_PLACES?: number; + + /** + * An integer, 0 to 8. Default value: `BigNumber.ROUND_HALF_UP` (4). + * + * The rounding mode used in operations that involve division (see `DECIMAL_PLACES`) and the + * default rounding mode of the `decimalPlaces`, `precision`, `toExponential`, `toFixed`, + * `toFormat` and `toPrecision` methods. + * + * The modes are available as enumerated properties of the BigNumber constructor. + * + * ```ts + * BigNumber.config({ ROUNDING_MODE: 0 }) + * BigNumber.set({ ROUNDING_MODE: BigNumber.ROUND_UP }) + * ``` + */ + ROUNDING_MODE?: BigNumberRoundingMode; + + /** + * An integer, 0 to 1e+9, or an array, [-1e+9 to 0, 0 to 1e+9]. + * Default value: `[-7, 20]`. + * + * The exponent value(s) at which `toString` returns exponential notation. + * + * If a single number is assigned, the value is the exponent magnitude. + * + * If an array of two numbers is assigned then the first number is the negative exponent value at + * and beneath which exponential notation is used, and the second number is the positive exponent + * value at and above which exponential notation is used. + * + * For example, to emulate JavaScript numbers in terms of the exponent values at which they begin + * to use exponential notation, use `[-7, 20]`. + * + * ```ts + * BigNumber.config({ EXPONENTIAL_AT: 2 }) + * new BigNumber(12.3) // '12.3' e is only 1 + * new BigNumber(123) // '1.23e+2' + * new BigNumber(0.123) // '0.123' e is only -1 + * new BigNumber(0.0123) // '1.23e-2' + * + * BigNumber.config({ EXPONENTIAL_AT: [-7, 20] }) + * new BigNumber(123456789) // '123456789' e is only 8 + * new BigNumber(0.000000123) // '1.23e-7' + * + * // Almost never return exponential notation: + * BigNumber.config({ EXPONENTIAL_AT: 1e+9 }) + * + * // Always return exponential notation: + * BigNumber.config({ EXPONENTIAL_AT: 0 }) + * ``` + * + * Regardless of the value of `EXPONENTIAL_AT`, the `toFixed` method will always return a value in + * normal notation and the `toExponential` method will always return a value in exponential form. + * Calling `toString` with a base argument, e.g. `toString(10)`, will also always return normal + * notation. + */ + EXPONENTIAL_AT?: number|[number, number]; + + /** + * An integer, magnitude 1 to 1e+9, or an array, [-1e+9 to -1, 1 to 1e+9]. + * Default value: `[-1e+9, 1e+9]`. + * + * The exponent value(s) beyond which overflow to Infinity and underflow to zero occurs. + * + * If a single number is assigned, it is the maximum exponent magnitude: values wth a positive + * exponent of greater magnitude become Infinity and those with a negative exponent of greater + * magnitude become zero. + * + * If an array of two numbers is assigned then the first number is the negative exponent limit and + * the second number is the positive exponent limit. + * + * For example, to emulate JavaScript numbers in terms of the exponent values at which they + * become zero and Infinity, use [-324, 308]. + * + * ```ts + * BigNumber.config({ RANGE: 500 }) + * BigNumber.config().RANGE // [ -500, 500 ] + * new BigNumber('9.999e499') // '9.999e+499' + * new BigNumber('1e500') // 'Infinity' + * new BigNumber('1e-499') // '1e-499' + * new BigNumber('1e-500') // '0' + * + * BigNumber.config({ RANGE: [-3, 4] }) + * new BigNumber(99999) // '99999' e is only 4 + * new BigNumber(100000) // 'Infinity' e is 5 + * new BigNumber(0.001) // '0.01' e is only -3 + * new BigNumber(0.0001) // '0' e is -4 + * ``` + * The largest possible magnitude of a finite BigNumber is 9.999...e+1000000000. + * The smallest possible magnitude of a non-zero BigNumber is 1e-1000000000. + */ + RANGE?: number|[number, number]; + + /** + * A boolean: `true` or `false`. Default value: `false`. + * + * The value that determines whether cryptographically-secure pseudo-random number generation is + * used. If `CRYPTO` is set to true then the random method will generate random digits using + * `crypto.getRandomValues` in browsers that support it, or `crypto.randomBytes` if using a + * version of Node.js that supports it. + * + * If neither function is supported by the host environment then attempting to set `CRYPTO` to + * `true` will fail and an exception will be thrown. + * + * If `CRYPTO` is `false` then the source of randomness used will be `Math.random` (which is + * assumed to generate at least 30 bits of randomness). + * + * See `BigNumber.random`. + * + * ```ts + * BigNumber.config({ CRYPTO: true }) + * BigNumber.config().CRYPTO // true + * BigNumber.random() // 0.54340758610486147524 + * ``` + */ + CRYPTO?: boolean; + + /** + * An integer, 0 to 9. Default value: `BigNumber.ROUND_DOWN` (1). + * + * The modulo mode used when calculating the modulus: `a mod n`. + * The quotient, `q = a / n`, is calculated according to the `ROUNDING_MODE` that corresponds to + * the chosen `MODULO_MODE`. + * The remainder, `r`, is calculated as: `r = a - n * q`. + * + * The modes that are most commonly used for the modulus/remainder operation are shown in the + * following table. Although the other rounding modes can be used, they may not give useful + * results. + * + * Property | Value | Description + * :------------------|:------|:------------------------------------------------------------------ + * `ROUND_UP` | 0 | The remainder is positive if the dividend is negative. + * `ROUND_DOWN` | 1 | The remainder has the same sign as the dividend. + * | | Uses 'truncating division' and matches JavaScript's `%` operator . + * `ROUND_FLOOR` | 3 | The remainder has the same sign as the divisor. + * | | This matches Python's `%` operator. + * `ROUND_HALF_EVEN` | 6 | The IEEE 754 remainder function. + * `EUCLID` | 9 | The remainder is always positive. + * | | Euclidian division: `q = sign(n) * floor(a / abs(n))` + * + * The rounding/modulo modes are available as enumerated properties of the BigNumber constructor. + * + * See `modulo`. + * + * ```ts + * BigNumber.config({ MODULO_MODE: BigNumber.EUCLID }) + * BigNumber.set({ MODULO_MODE: 9 }) // equivalent + * ``` + */ + MODULO_MODE?: BigNumberModuloMode; + + /** + * An integer, 0 to 1e+9. Default value: 0. + * + * The maximum precision, i.e. number of significant digits, of the result of the power operation + * - unless a modulus is specified. + * + * If set to 0, the number of significant digits will not be limited. + * + * See `exponentiatedBy`. + * + * ```ts + * BigNumber.config({ POW_PRECISION: 100 }) + * ``` + */ + POW_PRECISION?: number; + + /** + * An object including any number of the properties shown below. + * + * The object configures the format of the string returned by the `toFormat` method. + * The example below shows the properties of the object that are recognised, and + * their default values. + * + * Unlike the other configuration properties, the values of the properties of the `FORMAT` object + * will not be checked for validity - the existing object will simply be replaced by the object + * that is passed in. + * + * See `toFormat`. + * + * ```ts + * BigNumber.config({ + * FORMAT: { + * // the decimal separator + * decimalSeparator: '.', + * // the grouping separator of the integer part + * groupSeparator: ',', + * // the primary grouping size of the integer part + * groupSize: 3, + * // the secondary grouping size of the integer part + * secondaryGroupSize: 0, + * // the grouping separator of the fraction part + * fractionGroupSeparator: ' ', + * // the grouping size of the fraction part + * fractionGroupSize: 0 + * } + * }) + * ``` + */ + FORMAT?: BigNumberFormat; + + /** + * A string representing the alphabet used for base conversion. + * Default value: `'0123456789abcdefghijklmnopqrstuvwxyz'`. + * + * The length of the alphabet corresponds to the maximum value of the base argument that can be + * passed to the BigNumber constructor or `toString`. There is no maximum length, but it must be + * at least 2 characters long, and it must not contain a repeated character, or `'.'` - the + * decimal separator for all values whatever their base. + * + * ```ts + * // duodecimal (base 12) + * BigNumber.config({ ALPHABET: '0123456789TE' }) + * x = new BigNumber('T', 12) + * x.toString() // '10' + * x.toString(12) // 'T' + * ``` + */ + ALPHABET?: string; +} + + +/** + * See `FORMAT` and `toFormat`. + */ +interface BigNumberFormat { + + /** + * The decimal separator. + */ + decimalSeparator?: string; + + /** + * The grouping separator of the integer part. + */ + groupSeparator?: string; + + /** + * The primary grouping size of the integer part. + */ + groupSize?: number; + + /** + * The secondary grouping size of the integer part. + */ + secondaryGroupSize?: number; + + /** + * The grouping separator of the fraction part. + */ + fractionGroupSeparator?: string; + + /** + * The grouping size of the fraction part. + */ + fractionGroupSize?: number; +} + + +export declare class BigNumber { + + /** + * Used internally by the `BigNumber.isBigNumber` method. + */ + private readonly _isBigNumber: true; + + /** + * The coefficient of the value of this BigNumber, an array of base 1e14 integer numbers. + */ + readonly c: number[]; + + /** + * The exponent of the value of this BigNumber, an integer number, -1000000000 to 1000000000. + */ + readonly e: number; + + /** + * The sign of the value of this BigNumber, -1 or 1. + */ + readonly s: number; + + /** + * Returns a new instance of BigNumber with value `n`. + * + * Legitimate values for `n` include ±0, ±`Infinity` and `NaN`. + * + * Values of type number with more than 15 significant digits are considered invalid as calling + * `toString` or `valueOf` on such numbers may not result in the intended value. + * + * ```ts + * console.log( 823456789123456.3 ); // 823456789123456.2 + * ``` + * + * There is no limit to the number of digits of a value of type string (other than that of + * JavaScript's maximum array size). Decimal string values may be in exponential, as well as + * normal (fixed-point) notation. Non-decimal values must be in normal notation. + * + * String values in hexadecimal literal form, e.g. '0xff', are valid, as are string values with + * the octal and binary prefixs '0o' and '0b'. String values in octal literal form without the + * prefix will be interpreted as decimals, e.g. '011' is interpreted as 11, not 9. + * + * Values in any base may have fraction digits. + * + * If a base is specified, `n` is rounded according to the current `DECIMAL_PLACES` and + * `ROUNDING_MODE` settings. If base is omitted, or is `null` or `undefined`, base 10 is assumed. + * + * Throws an invalid `value` or `base`. + * + * ```ts + * x = new BigNumber(9) // '9' + * y = new BigNumber(x) // '9' + * + * // 'new' is optional + * BigNumber(435.345) // '435.345' + * + * new BigNumber('5032485723458348569331745.33434346346912144534543') + * new BigNumber('4.321e+4') // '43210' + * new BigNumber('-735.0918e-430') // '-7.350918e-428' + * new BigNumber(Infinity) // 'Infinity' + * new BigNumber(NaN) // 'NaN' + * new BigNumber('.5') // '0.5' + * new BigNumber('+2') // '2' + * new BigNumber(-10110100.1, 2) // '-180.5' + * new BigNumber(-0b10110100.1) // '-180.5' + * new BigNumber('123412421.234324', 5) // '607236.557696' + * new BigNumber('ff.8', 16) // '255.5' + * new BigNumber('0xff.8') // '255.5' + * + * // The following throws 'Not a base 2 number'. + * new BigNumber(9, 2) + * + * // The following throws 'Number primitive has more than 15 significant digits'. + * new BigNumber(96517860459076817.4395) + * + * // The following throws 'Not a number'. + * new BigNumber('blurgh') + * + * // A value is only rounded by the constructor if a base is specified. + * BigNumber.config({ DECIMAL_PLACES: 5 }) + * new BigNumber(1.23456789) // '1.23456789' + * new BigNumber(1.23456789, 10) // '1.23457' + * ``` + * + * @param n A numeric value. + * @param base The base of n, integer, 2 to 36 (or `ALPHABET.length`, see `ALPHABET`). + */ + constructor(n: BigNumberValue, base?: number); + + /** + * Returns a BigNumber whose value is the absolute value, i.e. the magnitude, of the value of this + * BigNumber. + * + * The return value is always exact and unrounded. + * + * ```ts + * x = new BigNumber(-0.8) + * x.absoluteValue() // '0.8' + * ``` + */ + absoluteValue(): BigNumber; + + /** + * Returns a BigNumber whose value is the absolute value, i.e. the magnitude, of the value of this + * BigNumber. + * + * The return value is always exact and unrounded. + * + * ```ts + * x = new BigNumber(-0.8) + * x.abs() // '0.8' + * ``` + */ + abs(): BigNumber; + + /** + * Returns | | + * :-------:|:--------------------------------------------------------------| + * 1 | If the value of this BigNumber is greater than the value of `n` + * -1 | If the value of this BigNumber is less than the value of `n` + * 0 | If this BigNumber and `n` have the same value + * `null` | If the value of either this BigNumber or `n` is `NaN` + * + * ```ts + * + * x = new BigNumber(Infinity) + * y = new BigNumber(5) + * x.comparedTo(y) // 1 + * x.comparedTo(x.minus(1)) // 0 + * y.comparedTo(NaN) // null + * y.comparedTo('110', 2) // -1 + * ``` + * @param n A numeric value. + * @param [base] The base of n. + */ + comparedTo(n: BigNumberValue, base?: number): number; + + /** + * Returns a BigNumber whose value is the value of this BigNumber rounded by rounding mode + * `roundingMode` to a maximum of `decimalPlaces` decimal places. + * + * If `decimalPlaces` is omitted, or is `null` or `undefined`, the return value is the number of + * decimal places of the value of this BigNumber, or `null` if the value of this BigNumber is + * ±`Infinity` or `NaN`. + * + * If `roundingMode` is omitted, or is `null` or `undefined`, `ROUNDING_MODE` is used. + * + * Throws if `decimalPlaces` or `roundingMode` is invalid. + * + * ```ts + * x = new BigNumber(1234.56) + * x.decimalPlaces() // 2 + * x.decimalPlaces(1) // '1234.6' + * x.decimalPlaces(2) // '1234.56' + * x.decimalPlaces(10) // '1234.56' + * x.decimalPlaces(0, 1) // '1234' + * x.decimalPlaces(0, 6) // '1235' + * x.decimalPlaces(1, 1) // '1234.5' + * x.decimalPlaces(1, BigNumber.ROUND_HALF_EVEN) // '1234.6' + * x // '1234.56' + * y = new BigNumber('9.9e-101') + * y.decimalPlaces() // 102 + * ``` + * + * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. + * @param [roundingMode] Rounding mode, integer, 0 to 8. + */ + decimalPlaces(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber rounded by rounding mode + * `roundingMode` to a maximum of `decimalPlaces` decimal places. + * + * If `decimalPlaces` is omitted, or is `null` or `undefined`, the return value is the number of + * decimal places of the value of this BigNumber, or `null` if the value of this BigNumber is + * ±`Infinity` or `NaN`. + * + * If `roundingMode` is omitted, or is `null` or `undefined`, `ROUNDING_MODE` is used. + * + * Throws if `decimalPlaces` or `roundingMode` is invalid. + * + * ```ts + * x = new BigNumber(1234.56) + * x.dp() // 2 + * x.dp(1) // '1234.6' + * x.dp(2) // '1234.56' + * x.dp(10) // '1234.56' + * x.dp(0, 1) // '1234' + * x.dp(0, 6) // '1235' + * x.dp(1, 1) // '1234.5' + * x.dp(1, BigNumber.ROUND_HALF_EVEN) // '1234.6' + * x // '1234.56' + * y = new BigNumber('9.9e-101') + * y.dp() // 102 + * ``` + * + * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. + * @param [roundingMode] Rounding mode, integer, 0 to 8. + */ + dp(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber divided by `n`, rounded + * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. + * + * ```ts + * x = new BigNumber(355) + * y = new BigNumber(113) + * x.dividedBy(y) // '3.14159292035398230088' + * x.dividedBy(5) // '71' + * x.dividedBy(47, 16) // '5' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + dividedBy(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber divided by `n`, rounded + * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. + * + * ```ts + * x = new BigNumber(355) + * y = new BigNumber(113) + * x.div(y) // '3.14159292035398230088' + * x.div(5) // '71' + * x.div(47, 16) // '5' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + div(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the integer part of dividing the value of this BigNumber by + * `n`. + * + * ```ts + * x = new BigNumber(5) + * y = new BigNumber(3) + * x.dividedToIntegerBy(y) // '1' + * x.dividedToIntegerBy(0.7) // '7' + * x.dividedToIntegerBy('0.f', 16) // '5' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + dividedToIntegerBy(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the integer part of dividing the value of this BigNumber by + * `n`. + * + * ```ts + * x = new BigNumber(5) + * y = new BigNumber(3) + * x.idiv(y) // '1' + * x.idiv(0.7) // '7' + * x.idiv('0.f', 16) // '5' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + idiv(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber exponentiated by `n`, i.e. + * raised to the power `n`, and optionally modulo a modulus `m`. + * + * If `n` is negative the result is rounded according to the current `DECIMAL_PLACES` and + * `ROUNDING_MODE` settings. + * + * As the number of digits of the result of the power operation can grow so large so quickly, + * e.g. 123.456**10000 has over 50000 digits, the number of significant digits calculated is + * limited to the value of the `POW_PRECISION` setting (unless a modulus `m` is specified). + * + * By default `POW_PRECISION` is set to 0. This means that an unlimited number of significant + * digits will be calculated, and that the method's performance will decrease dramatically for + * larger exponents. + * + * If `m` is specified and the value of `m`, `n` and this BigNumber are positive integers, then a + * fast modular exponentiation algorithm is used, otherwise if any of the values is not a positive + * integer the operation will simply be performed as `x.exponentiatedBy(n).modulo(m)` with a + * `POW_PRECISION` of 0. + * + * Throws if `n` is not a primitive number, or is not an integer, or is out of range. + * + * ```ts + * Math.pow(0.7, 2) // 0.48999999999999994 + * x = new BigNumber(0.7) + * x.exponentiatedBy(2) // '0.49' + * BigNumber(3).exponentiatedBy(-2) // '0.11111111111111111111' + * ``` + * + * @param n The exponent, an integer, -9007199254740991 to 9007199254740991. + * @param [m] The modulus, a positive integer. + */ + exponentiatedBy(n: number, m?: BigNumberValue): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber exponentiated by `n`, i.e. + * raised to the power `n`, and optionally modulo a modulus `m`. + * + * If `n` is negative the result is rounded according to the current `DECIMAL_PLACES` and + * `ROUNDING_MODE` settings. + * + * As the number of digits of the result of the power operation can grow so large so quickly, + * e.g. 123.456**10000 has over 50000 digits, the number of significant digits calculated is + * limited to the value of the `POW_PRECISION` setting (unless a modulus `m` is specified). + * + * By default `POW_PRECISION` is set to 0. This means that an unlimited number of significant + * digits will be calculated, and that the method's performance will decrease dramatically for + * larger exponents. + * + * If `m` is specified and the value of `m`, `n` and this BigNumber are positive integers, then a + * fast modular exponentiation algorithm is used, otherwise if any of the values is not a positive + * integer the operation will simply be performed as `x.exponentiatedBy(n).modulo(m)` with a + * `POW_PRECISION` of 0. + * + * Throws if `n` is not a primitive number or an integer, or is out of range. + * + * ```ts + * Math.pow(0.7, 2) // 0.48999999999999994 + * x = new BigNumber(0.7) + * x.pow(2) // '0.49' + * BigNumber(3).pow(-2) // '0.11111111111111111111' + * ``` + * + * @param n The exponent, an integer, -9007199254740991 to 9007199254740991. + * @param [m] The modulus, a positive integer. + */ + pow(n: number, m?: BigNumberValue): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber rounded to an integer using + * rounding mode `rm`. + * + * If `rm` is omitted, or is `null` or `undefined`, `ROUNDING_MODE` is used. + * + * Throws if `rm` is invalid. + * + * ```ts + * x = new BigNumber(123.456) + * x.integerValue() // '123' + * x.integerValue(BigNumber.ROUND_CEIL) // '124' + * y = new BigNumber(-12.7) + * y.integerValue() // '-13' + * x.integerValue(BigNumber.ROUND_DOWN) // '-12' + * ``` + * + * @param {BigNumberRoundingMode} [rm] The roundng mode, an integer, 0 to 8. + */ + integerValue(rm?: BigNumberRoundingMode): BigNumber; + + /** + * Returns `true` if the value of this BigNumber is equal to the value of `n`, otherwise returns + * `false`. + * + * As with JavaScript, `NaN` does not equal `NaN`. + * + * ```ts + * 0 === 1e-324 // true + * x = new BigNumber(0) + * x.isEqualTo('1e-324') // false + * BigNumber(-0).isEqualTo(x) // true ( -0 === 0 ) + * BigNumber(255).isEqualTo('ff', 16) // true + * + * y = new BigNumber(NaN) + * y.isEqualTo(NaN) // false + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + isEqualTo(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is equal to the value of `n`, otherwise returns + * `false`. + * + * As with JavaScript, `NaN` does not equal `NaN`. + * + * ```ts + * 0 === 1e-324 // true + * x = new BigNumber(0) + * x.eq('1e-324') // false + * BigNumber(-0).eq(x) // true ( -0 === 0 ) + * BigNumber(255).eq('ff', 16) // true + * + * y = new BigNumber(NaN) + * y.eq(NaN) // false + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + eq(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is a finite number, otherwise returns `false`. + * + * The only possible non-finite values of a BigNumber are `NaN`, `Infinity` and `-Infinity`. + * + * ```ts + * x = new BigNumber(1) + * x.isFinite() // true + * y = new BigNumber(Infinity) + * y.isFinite() // false + * ``` + */ + isFinite(): boolean; + + /** + * Returns `true` if the value of this BigNumber is greater than the value of `n`, otherwise + * returns `false`. + * + * ```ts + * 0.1 > (0.3 - 0.2) // true + * x = new BigNumber(0.1) + * x.isGreaterThan(BigNumber(0.3).minus(0.2)) // false + * BigNumber(0).isGreaterThan(x) // false + * BigNumber(11, 3).isGreaterThan(11.1, 2) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + isGreaterThan(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is greater than the value of `n`, otherwise + * returns `false`. + * + * ```ts + * 0.1 > (0.3 - 0 // true + * x = new BigNumber(0.1) + * x.gt(BigNumber(0.3).minus(0.2)) // false + * BigNumber(0).gt(x) // false + * BigNumber(11, 3).gt(11.1, 2) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + gt(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is greater than or equal to the value of `n`, + * otherwise returns `false`. + * + * ```ts + * (0.3 - 0.2) >= 0.1 // false + * x = new BigNumber(0.3).minus(0.2) + * x.isGreaterThanOrEqualTo(0.1) // true + * BigNumber(1).isGreaterThanOrEqualTo(x) // true + * BigNumber(10, 18).isGreaterThanOrEqualTo('i', 36) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + isGreaterThanOrEqualTo(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is greater than or equal to the value of `n`, + * otherwise returns `false`. + * + * ```ts + * (0.3 - 0.2) >= 0.1 // false + * x = new BigNumber(0.3).minus(0.2) + * x.gte(0.1) // true + * BigNumber(1).gte(x) // true + * BigNumber(10, 18).gte('i', 36) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + gte(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is an integer, otherwise returns `false`. + * + * ```ts + * x = new BigNumber(1) + * x.isInteger() // true + * y = new BigNumber(123.456) + * y.isInteger() // false + * ``` + */ + isInteger(): boolean; + + /** + * Returns `true` if the value of this BigNumber is less than the value of `n`, otherwise returns + * `false`. + * + * ```ts + * (0.3 - 0.2) < 0.1 // true + * x = new BigNumber(0.3).minus(0.2) + * x.isLessThan(0.1) // false + * BigNumber(0).isLessThan(x) // true + * BigNumber(11.1, 2).isLessThan(11, 3) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + isLessThan(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is less than the value of `n`, otherwise returns + * `false`. + * + * ```ts + * (0.3 - 0.2) < 0.1 // true + * x = new BigNumber(0.3).minus(0.2) + * x.lt(0.1) // false + * BigNumber(0).lt(x) // true + * BigNumber(11.1, 2).lt(11, 3) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + lt(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is less than or equal to the value of `n`, + * otherwise returns `false`. + * + * ```ts + * 0.1 <= (0.3 - 0.2) // false + * x = new BigNumber(0.1) + * x.isLessThanOrEqualTo(BigNumber(0.3).minus(0.2)) // true + * BigNumber(-1).isLessThanOrEqualTo(x) // true + * BigNumber(10, 18).isLessThanOrEqualTo('i', 36) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + isLessThanOrEqualTo(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is less than or equal to the value of `n`, + * otherwise returns `false`. + * + * ```ts + * 0.1 <= (0.3 - 0.2) // false + * x = new BigNumber(0.1) + * x.lte(BigNumber(0.3).minus(0.2)) // true + * BigNumber(-1).lte(x) // true + * BigNumber(10, 18).lte('i', 36) // true + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + lte(n: BigNumberValue, base?: number): boolean; + + /** + * Returns `true` if the value of this BigNumber is `NaN`, otherwise returns `false`. + * + * ```ts + * x = new BigNumber(NaN) + * x.isNaN() // true + * y = new BigNumber('Infinity') + * y.isNaN() // false + * ``` + */ + isNaN(): boolean; + + /** + * Returns `true` if the value of this BigNumber is negative, otherwise returns `false`. + * + * ```ts + * x = new BigNumber(-0) + * x.isNegative() // true + * y = new BigNumber(2) + * y.isNegative() // false + * ``` + */ + isNegative(): boolean; + + /** + * Returns `true` if the value of this BigNumber is positive, otherwise returns `false`. + * + * ```ts + * x = new BigNumber(-0) + * x.isPositive() // false + * y = new BigNumber(2) + * y.isPositive() // true + * ``` + */ + isPositive(): boolean; + + /** + * Returns `true` if the value of this BigNumber is zero or minus zero, otherwise returns `false`. + * + * ```ts + * x = new BigNumber(-0) + * x.isZero() // true + * ``` + */ + isZero(): boolean; + + /** + * Returns a BigNumber whose value is the value of this BigNumber minus `n`. + * + * The return value is always exact and unrounded. + * + * ```ts + * 0.3 - 0.1 // 0.19999999999999998 + * x = new BigNumber(0.3) + * x.minus(0.1) // '0.2' + * x.minus(0.6, 20) // '0' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + minus(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber modulo `n`, i.e. the integer + * remainder of dividing this BigNumber by `n`. + * + * The value returned, and in particular its sign, is dependent on the value of the `MODULO_MODE` + * setting of this BigNumber constructor. If it is 1 (default value), the result will have the + * same sign as this BigNumber, and it will match that of Javascript's `%` operator (within the + * limits of double precision) and BigDecimal's `remainder` method. + * + * The return value is always exact and unrounded. + * + * See `MODULO_MODE` for a description of the other modulo modes. + * + * ```ts + * 1 % 0.9 // 0.09999999999999998 + * x = new BigNumber(1) + * x.modulo(0.9) // '0.1' + * y = new BigNumber(33) + * y.modulo('a', 33) // '3' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + modulo(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber modulo `n`, i.e. the integer + * remainder of dividing this BigNumber by `n`. + * + * The value returned, and in particular its sign, is dependent on the value of the `MODULO_MODE` + * setting of this BigNumber constructor. If it is 1 (default value), the result will have the + * same sign as this BigNumber, and it will match that of Javascript's `%` operator (within the + * limits of double precision) and BigDecimal's `remainder` method. + * + * The return value is always exact and unrounded. + * + * See `MODULO_MODE` for a description of the other modulo modes. + * + * ```ts + * 1 % 0.9 // 0.09999999999999998 + * x = new BigNumber(1) + * x.mod(0.9) // '0.1' + * y = new BigNumber(33) + * y.mod('a', 33) // '3' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + mod(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber multiplied by `n`. + * + * The return value is always exact and unrounded. + * + * ```ts + * 0.6 * 3 // 1.7999999999999998 + * x = new BigNumber(0.6) + * y = x.multipliedBy(3) // '1.8' + * BigNumber('7e+500').multipliedBy(y) // '1.26e+501' + * x.multipliedBy('-a', 16) // '-6' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + multipliedBy(n: BigNumberValue, base?: number) : BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber multiplied by `n`. + * + * The return value is always exact and unrounded. + * + * ```ts + * 0.6 * 3 // 1.7999999999999998 + * x = new BigNumber(0.6) + * y = x.times(3) // '1.8' + * BigNumber('7e+500').times(y) // '1.26e+501' + * x.times('-a', 16) // '-6' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + times(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber negated, i.e. multiplied by -1. + * + * ```ts + * x = new BigNumber(1.8) + * x.negated() // '-1.8' + * y = new BigNumber(-1.3) + * y.negated() // '1.3' + * ``` + */ + negated(): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber plus `n`. + * + * The return value is always exact and unrounded. + * + * ```ts + * 0.1 + 0.2 // 0.30000000000000004 + * x = new BigNumber(0.1) + * y = x.plus(0.2) // '0.3' + * BigNumber(0.7).plus(x).plus(y) // '1' + * x.plus('0.1', 8) // '0.225' + * ``` + * + * @param n A numeric value. + * @param [base] The base of n. + */ + plus(n: BigNumberValue, base?: number): BigNumber; + + /** + * Returns the number of significant digits of the value of this BigNumber, or `null` if the value + * of this BigNumber is ±`Infinity` or `NaN`. + * + * If `includeZeros` is true then any trailing zeros of the integer part of the value of this + * BigNumber are counted as significant digits, otherwise they are not. + * + * Throws if `includeZeros` is invalid. + * + * ```ts + * x = new BigNumber(9876.54321) + * x.precision() // 9 + * y = new BigNumber(987000) + * y.precision(false) // 3 + * y.precision(true) // 6 + * ``` + * + * @param [includeZeros] Whether to include integer trailing zeros in the significant digit count. + */ + precision(includeZeros?: boolean): number; + + /** + * Returns a BigNumber whose value is the value of this BigNumber rounded to a precision of + * `significantDigits` significant digits using rounding mode `roundingMode`. + * + * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` will be used. + * + * Throws if `significantDigits` or `roundingMode` is invalid. + * + * ```ts + * x = new BigNumber(9876.54321) + * x.precision(6) // '9876.54' + * x.precision(6, BigNumber.ROUND_UP) // '9876.55' + * x.precision(2) // '9900' + * x.precision(2, 1) // '9800' + * x // '9876.54321' + * ``` + * + * @param significantDigits Significant digits, integer, 1 to 1e+9. + * @param [roundingMode] Rounding mode, integer, 0 to 8. + */ + precision(significantDigits: number, roundingMode?: BigNumberRoundingMode): BigNumber; + + /** + * Returns the number of significant digits of the value of this BigNumber, + * or `null` if the value of this BigNumber is ±`Infinity` or `NaN`. + * + * If `includeZeros` is true then any trailing zeros of the integer part of + * the value of this BigNumber are counted as significant digits, otherwise + * they are not. + * + * Throws if `includeZeros` is invalid. + * + * ```ts + * x = new BigNumber(9876.54321) + * x.sd() // 9 + * y = new BigNumber(987000) + * y.sd(false) // 3 + * y.sd(true) // 6 + * ``` + * + * @param [includeZeros] Whether to include integer trailing zeros in the significant digit count. + */ + sd(includeZeros?: boolean): number; + + /* + * Returns a BigNumber whose value is the value of this BigNumber rounded to a precision of + * `significantDigits` significant digits using rounding mode `roundingMode`. + * + * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` will be used. + * + * Throws if `significantDigits` or `roundingMode` is invalid. + * + * ```ts + * x = new BigNumber(9876.54321) + * x.sd(6) // '9876.54' + * x.sd(6, BigNumber.ROUND_UP) // '9876.55' + * x.sd(2) // '9900' + * x.sd(2, 1) // '9800' + * x // '9876.54321' + * ``` + * + * @param significantDigits Significant digits, integer, 1 to 1e+9. + * @param [roundingMode] Rounding mode, integer, 0 to 8. + */ + sd(significantDigits: number, roundingMode?: BigNumberRoundingMode): BigNumber; + + /** + * Returns a BigNumber whose value is the value of this BigNumber shifted by `n` places. + * + * The shift is of the decimal point, i.e. of powers of ten, and is to the left if `n` is negative + * or to the right if `n` is positive. + * + * The return value is always exact and unrounded. + * + * Throws if `n` is invalid. + * + * ```ts + * x = new BigNumber(1.23) + * x.shiftedBy(3) // '1230' + * x.shiftedBy(-3) // '0.00123' + * ``` + * + * @param n The shift value, integer, -9007199254740991 to 9007199254740991. + */ + shiftedBy(n: number): BigNumber; + + /** + * Returns a BigNumber whose value is the square root of the value of this BigNumber, rounded + * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. + * + * The return value will be correctly rounded, i.e. rounded as if the result was first calculated + * to an infinite number of correct digits before rounding. + * + * ```ts + * x = new BigNumber(16) + * x.squareRoot() // '4' + * y = new BigNumber(3) + * y.squareRoot() // '1.73205080756887729353' + * ``` + */ + squareRoot(): BigNumber; + + /** + * Returns a BigNumber whose value is the square root of the value of this BigNumber, rounded + * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. + * + * The return value will be correctly rounded, i.e. rounded as if the result was first calculated + * to an infinite number of correct digits before rounding. + * + * ```ts + * x = new BigNumber(16) + * x.sqrt() // '4' + * y = new BigNumber(3) + * y.sqrt() // '1.73205080756887729353' + * ``` + */ + sqrt(): BigNumber; + + /** + * Returns a string representing the value of this BigNumber in exponential notation rounded using + * rounding mode `roundingMode` to `decimalPlaces` decimal places, i.e with one digit before the + * decimal point and `decimalPlaces` digits after it. + * + * If the value of this BigNumber in exponential notation has fewer than `decimalPlaces` fraction + * digits, the return value will be appended with zeros accordingly. + * + * If `decimalPlaces` is omitted, or is `null` or `undefined`, the number of digits after the + * decimal point defaults to the minimum number of digits necessary to represent the value + * exactly. + * + * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. + * + * Throws if `decimalPlaces` or `roundingMode` is invalid. + * + * ```ts + * x = 45.6 + * y = new BigNumber(x) + * x.toExponential() // '4.56e+1' + * y.toExponential() // '4.56e+1' + * x.toExponential(0) // '5e+1' + * y.toExponential(0) // '5e+1' + * x.toExponential(1) // '4.6e+1' + * y.toExponential(1) // '4.6e+1' + * y.toExponential(1, 1) // '4.5e+1' (ROUND_DOWN) + * x.toExponential(3) // '4.560e+1' + * y.toExponential(3) // '4.560e+1' + * ``` + * + * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. + * @param [roundingMode] Rounding mode, integer, 0 to 8. + */ + toExponential(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): string; + + /** + * Returns a string representing the value of this BigNumber in normal (fixed-point) notation + * rounded to `decimalPlaces` decimal places using rounding mode `roundingMode`. + * + * If the value of this BigNumber in normal notation has fewer than `decimalPlaces` fraction + * digits, the return value will be appended with zeros accordingly. + * + * Unlike `Number.prototype.toFixed`, which returns exponential notation if a number is greater or + * equal to 10**21, this method will always return normal notation. + * + * If `decimalPlaces` is omitted or is `null` or `undefined`, the return value will be unrounded + * and in normal notation. This is also unlike `Number.prototype.toFixed`, which returns the value + * to zero decimal places. It is useful when normal notation is required and the current + * `EXPONENTIAL_AT` setting causes `toString` to return exponential notation. + * + * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. + * + * Throws if `decimalPlaces` or `roundingMode` is invalid. + * + * ```ts + * x = 3.456 + * y = new BigNumber(x) + * x.toFixed() // '3' + * y.toFixed() // '3.456' + * y.toFixed(0) // '3' + * x.toFixed(2) // '3.46' + * y.toFixed(2) // '3.46' + * y.toFixed(2, 1) // '3.45' (ROUND_DOWN) + * x.toFixed(5) // '3.45600' + * y.toFixed(5) // '3.45600' + * ``` + * + * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. + * @param [roundingMode] Rounding mode, integer, 0 to 8. + */ + toFixed(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): string; + + /** + * Returns a string representing the value of this BigNumber in normal (fixed-point) notation + * rounded to `decimalPlaces` decimal places using rounding mode `roundingMode`, and formatted + * according to the properties of the `FORMAT` object. + * + * The properties of the `FORMAT` object are shown in the examples below. + * + * If `decimalPlaces` is omitted or is `null` or `undefined`, then the return value is not + * rounded to a fixed number of decimal places. + * + * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. + * + * Throws if `decimalPlaces` or `roundingMode` is invalid. + * + * ```ts + * format = { + * decimalSeparator: '.', + * groupSeparator: ',', + * groupSize: 3, + * secondaryGroupSize: 0, + * fractionGroupSeparator: ' ', + * fractionGroupSize: 0 + * } + * BigNumber.config({ FORMAT: format }) + * + * x = new BigNumber('123456789.123456789') + * x.toFormat() // '123,456,789.123456789' + * x.toFormat(1) // '123,456,789.1' + * + * format.groupSeparator = ' ' + * format.fractionGroupSize = 5 + * x.toFormat() // '123 456 789.12345 6789' + * + * BigNumber.config({ + * FORMAT: { + * decimalSeparator: ',', + * groupSeparator: '.', + * groupSize: 3, + * secondaryGroupSize: 2 + * } + * }) + * + * x.toFormat(6) // '12.34.56.789,123' + * ``` + * + * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. + * @param [roundingMode] Rounding mode, integer, 0 to 8. + */ + toFormat(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): string; + + /** + * Returns a string array representing the value of this BigNumber as a simple fraction with an + * integer numerator and an integer denominator. The denominator will be a positive non-zero value + * less than or equal to `max_denominator`. + * + * If a maximum denominator, `max_denominator`, is not specified, or is `null` or `undefined`, the + * denominator will be the lowest value necessary to represent the number exactly. + * + * Throws if `max_denominator` is invalid. + * + * ```ts + * x = new BigNumber(1.75) + * x.toFraction() // '7, 4' + * + * pi = new BigNumber('3.14159265358') + * pi.toFraction() // '157079632679,50000000000' + * pi.toFraction(100000) // '312689, 99532' + * pi.toFraction(10000) // '355, 113' + * pi.toFraction(100) // '311, 99' + * pi.toFraction(10) // '22, 7' + * pi.toFraction(1) // '3, 1' + * ``` + * + * @param [max_denominator] The maximum denominator, integer, >= 1 and < Infinity. + */ + toFraction(max_denominator?: BigNumberValue): BigNumber[]; + + /** + * As `valueOf`. + */ + toJSON(): string; + + /** + * Returns the value of this BigNumber as a JavaScript primitive number. + * + * Using the unary plus operator gives the same result. + * + * ```ts + * x = new BigNumber(456.789) + * x.toNumber() // 456.789 + * +x // 456.789 + * + * y = new BigNumber('45987349857634085409857349856430985') + * y.toNumber() // 4.598734985763409e+34 + * + * z = new BigNumber(-0) + * 1 / z.toNumber() // -Infinity + * 1 / +z // -Infinity + * ``` + */ + toNumber(): number; + + /** + * Returns a string representing the value of this BigNumber rounded to `significantDigits` + * significant digits using rounding mode `roundingMode`. + * + * If `significantDigits` is less than the number of digits necessary to represent the integer + * part of the value in normal (fixed-point) notation, then exponential notation is used. + * + * If `significantDigits` is omitted, or is `null` or `undefined`, then the return value is the + * same as `n.toString()`. + * + * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. + * + * Throws if `significantDigits` or `roundingMode` is invalid. + * + * ```ts + * x = 45.6 + * y = new BigNumber(x) + * x.toPrecision() // '45.6' + * y.toPrecision() // '45.6' + * x.toPrecision(1) // '5e+1' + * y.toPrecision(1) // '5e+1' + * y.toPrecision(2, 0) // '4.6e+1' (ROUND_UP) + * y.toPrecision(2, 1) // '4.5e+1' (ROUND_DOWN) + * x.toPrecision(5) // '45.600' + * y.toPrecision(5) // '45.600' + * ``` + * + * @param [significantDigits] Significant digits, integer, 1 to 1e+9. + * @param [roundingMode] Rounding mode, integer 0 to 8. + */ + toPrecision(significantDigits?: number, roundingMode?: BigNumberRoundingMode): string; + + /** + * Returns a string representing the value of this BigNumber in base `base`, or base 10 if `base` + * is omitted or is `null` or `undefined`. + * + * For bases above 10, and using the default base conversion alphabet (see `ALPHABET`), values + * from 10 to 35 are represented by a-z (the same as `Number.prototype.toString`). + * + * If a base is specified the value is rounded according to the current `DECIMAL_PLACES` and + * `ROUNDING_MODE` settings, otherwise it is not. + * + * If a base is not specified, and this BigNumber has a positive exponent that is equal to or + * greater than the positive component of the current `EXPONENTIAL_AT` setting, or a negative + * exponent equal to or less than the negative component of the setting, then exponential notation + * is returned. + * + * If `base` is `null` or `undefined` it is ignored. + * + * Throws if `base` is invalid. + * + * ```ts + * x = new BigNumber(750000) + * x.toString() // '750000' + * BigNumber.config({ EXPONENTIAL_AT: 5 }) + * x.toString() // '7.5e+5' + * + * y = new BigNumber(362.875) + * y.toString(2) // '101101010.111' + * y.toString(9) // '442.77777777777777777778' + * y.toString(32) // 'ba.s' + * + * BigNumber.config({ DECIMAL_PLACES: 4 }); + * z = new BigNumber('1.23456789') + * z.toString() // '1.23456789' + * z.toString(10) // '1.2346' + * ``` + * + * @param [base] The base, integer, 2 to 36 (or `ALPHABET.length`, see `ALPHABET`). + */ + toString(base?: number): string; + + /** + * As `toString`, but does not accept a base argument and includes the minus sign for negative + * zero. + * + * ``ts + * x = new BigNumber('-0') + * x.toString() // '0' + * x.valueOf() // '-0' + * y = new BigNumber('1.777e+457') + * y.valueOf() // '1.777e+457' + * ``` + */ + valueOf(): string; + + /** + * Returns a new independent BigNumber constructor with configuration as described by `object`, or + * with the default configuration if object is `null` or `undefined`. + * + * Throws if `object` is not an object. + * + * ```ts + * BigNumber.config({ DECIMAL_PLACES: 5 }) + * BN = BigNumber.clone({ DECIMAL_PLACES: 9 }) + * + * x = new BigNumber(1) + * y = new BN(1) + * + * x.div(3) // 0.33333 + * y.div(3) // 0.333333333 + * + * // BN = BigNumber.clone({ DECIMAL_PLACES: 9 }) is equivalent to: + * BN = BigNumber.clone() + * BN.config({ DECIMAL_PLACES: 9 }) + * ``` + * + * @param [object] The configuration object. + */ + static clone(object?: BigNumberConfig): BigNumberConstructor; + + /** + * Configures the settings that apply to this BigNumber constructor. + * + * The configuration object, `object`, contains any number of the properties shown in the example + * below. + * + * Returns an object with the above properties and their current values. + * + * Throws if `object` is not an object, or if an invalid value is assigned to one or more of the + * properties. + * + * ```ts + * BigNumber.config({ + * DECIMAL_PLACES: 40, + * ROUNDING_MODE: BigNumber.ROUND_HALF_CEIL, + * EXPONENTIAL_AT: [-10, 20], + * RANGE: [-500, 500], + * CRYPTO: true, + * MODULO_MODE: BigNumber.ROUND_FLOOR, + * POW_PRECISION: 80, + * FORMAT: { + * groupSize: 3, + * groupSeparator: ' ', + * decimalSeparator: ',' + * }, + * ALPHABET: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_' + * }); + * + * BigNumber.config().DECIMAL_PLACES // 40 + * ``` + * + * @param object The configuration object. + */ + static config(object: BigNumberConfig): BigNumberConfig; + + /** + * Returns `true` if `value` is a BigNumber instance, otherwise returns `false`. + * + * ```ts + * x = 42 + * y = new BigNumber(x) + * + * BigNumber.isBigNumber(x) // false + * y instanceof BigNumber // true + * BigNumber.isBigNumber(y) // true + * + * BN = BigNumber.clone(); + * z = new BN(x) + * z instanceof BigNumber // false + * BigNumber.isBigNumber(z) // true + * ``` + * + * @param value The value to test. + */ + static isBigNumber(value: any): boolean; + + /** + * + * Returns a BigNumber whose value is the maximum of the arguments. + * + * Accepts either an argument list or an array of values. + * + * The return value is always exact and unrounded. + * + * ```ts + * x = new BigNumber('3257869345.0378653') + * BigNumber.maximum(4e9, x, '123456789.9') // '4000000000' + * + * arr = [12, '13', new BigNumber(14)] + * BigNumber.maximum(arr) // '14' + * ``` + * + * @param n A numeric value. + */ + static maximum(...n: BigNumberValue[]): BigNumber; + + /** + * Returns a BigNumber whose value is the maximum of the arguments. + * + * Accepts either an argument list or an array of values. + * + * The return value is always exact and unrounded. + * + * ```ts + * x = new BigNumber('3257869345.0378653') + * BigNumber.max(4e9, x, '123456789.9') // '4000000000' + * + * arr = [12, '13', new BigNumber(14)] + * BigNumber.max(arr) // '14' + * ``` + * + * @param n A numeric value. + */ + static max(...n: BigNumberValue[]): BigNumber; + + /** + * Returns a BigNumber whose value is the minimum of the arguments. + * + * Accepts either an argument list or an array of values. + * + * The return value is always exact and unrounded. + * + * ```ts + * x = new BigNumber('3257869345.0378653') + * BigNumber.minimum(4e9, x, '123456789.9') // '123456789.9' + * + * arr = [2, new BigNumber(-14), '-15.9999', -12] + * BigNumber.minimum(arr) // '-15.9999' + * ``` + * + * @param n A numeric value. + */ + static minimum(...n: BigNumberValue[]): BigNumber; + + /** + * Returns a BigNumber whose value is the minimum of the arguments. + * + * Accepts either an argument list or an array of values. + * + * The return value is always exact and unrounded. + * + * ```ts + * x = new BigNumber('3257869345.0378653') + * BigNumber.min(4e9, x, '123456789.9') // '123456789.9' + * + * arr = [2, new BigNumber(-14), '-15.9999', -12] + * BigNumber.min(arr) // '-15.9999' + * ``` + * + * @param n A numeric value. + */ + static min(...n: BigNumberValue[]): BigNumber; + + /** + * Returns a new BigNumber with a pseudo-random value equal to or greater than 0 and less than 1. + * + * The return value will have `decimalPlaces` decimal places, or less if trailing zeros are + * produced. If `decimalPlaces` is omitted, the current `DECIMAL_PLACES` setting will be used. + * + * Depending on the value of this BigNumber constructor's `CRYPTO` setting and the support for the + * `crypto` object in the host environment, the random digits of the return value are generated by + * either `Math.random` (fastest), `crypto.getRandomValues` (Web Cryptography API in recent + * browsers) or `crypto.randomBytes` (Node.js). + * + * If `CRYPTO` is true, i.e. one of the `crypto` methods is to be used, the value of a returned + * BigNumber should be cryptographically secure and statistically indistinguishable from a random + * value. + * + * Throws if `decimalPlaces` is invalid. + * + * ```ts + * BigNumber.config({ DECIMAL_PLACES: 10 }) + * BigNumber.random() // '0.4117936847' + * BigNumber.random(20) // '0.78193327636914089009' + * ``` + * + * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. + */ + static random(decimalPlaces?: number): BigNumber; + + /** + * Configures the settings that apply to this BigNumber constructor. + * + * The configuration object, `object`, contains any number of the properties shown in the example + * below. + * + * Returns an object with the above properties and their current values. + * + * Throws if `object` is not an object, or if an invalid value is assigned to one or more of the + * properties. + * + * ```ts + * BigNumber.set({ + * DECIMAL_PLACES: 40, + * ROUNDING_MODE: BigNumber.ROUND_HALF_CEIL, + * EXPONENTIAL_AT: [-10, 20], + * RANGE: [-500, 500], + * CRYPTO: true, + * MODULO_MODE: BigNumber.ROUND_FLOOR, + * POW_PRECISION: 80, + * FORMAT: { + * groupSize: 3, + * groupSeparator: ' ', + * decimalSeparator: ',' + * }, + * ALPHABET: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_' + * }); + * + * BigNumber.set().DECIMAL_PLACES // 40 + * ``` + * + * @param object The configuration object. + */ + static set(object: BigNumberConfig): BigNumberConfig; + + /** + * Helps ES6 import. + */ + private static readonly default?: BigNumberConstructor; + + /** + * Helps ES6 import. + */ + private static readonly BigNumber?: BigNumberConstructor; + + /** + * Rounds away from zero. + */ + static readonly ROUND_UP: 0; + + /** + * Rounds towards zero. + */ + static readonly ROUND_DOWN: 1; + + /** + * Rounds towards Infinity. + */ + static readonly ROUND_CEIL: 2; + + /** + * Rounds towards -Infinity. + */ + static readonly ROUND_FLOOR: 3; + + /** + * Rounds towards nearest neighbour. If equidistant, rounds away from zero . + */ + static readonly ROUND_HALF_UP: 4; + + /** + * Rounds towards nearest neighbour. If equidistant, rounds towards zero. + */ + static readonly ROUND_HALF_DOWN: 5; + + /** + * Rounds towards nearest neighbour. If equidistant, rounds towards even neighbour. + */ + static readonly ROUND_HALF_EVEN: 6; + + /** + * Rounds towards nearest neighbour. If equidistant, rounds towards Infinity. + */ + static readonly ROUND_HALF_CEIL: 7; + + /** + * Rounds towards nearest neighbour. If equidistant, rounds towards -Infinity. + */ + static readonly ROUND_HALF_FLOOR: 8; + + /** + * See `MODULO_MODE`. + */ + static readonly EUCLID: 9; +} + + +export default BigNumber; + +export namespace BigNumber { + export type Config = BigNumberConfig; + export type Constructor = BigNumberConstructor; + export type Format = BigNumberFormat; + export type Instance = BigNumberInstance; + export type ModuloMode = BigNumberModuloMode; + export type RoundingMode = BigNumberRoundingMode; + export type Value = BigNumberValue; +} + +/** + * Browsers. + */ +declare global { + const BigNumber: BigNumberConstructor; + type BigNumber = BigNumberInstance; + + namespace BigNumber { + type Config = BigNumberConfig; + type Constructor = BigNumberConstructor; + type Format = BigNumberFormat; + type Instance = BigNumberInstance; + type ModuloMode = BigNumberModuloMode; + type RoundingMode = BigNumberRoundingMode; + type Value = BigNumberValue; + } +} \ No newline at end of file diff --git a/packages/instant/test/util/dependencies/prevbignumber.js b/packages/instant/test/util/dependencies/prevbignumber.js new file mode 100644 index 0000000000..e2d3f21466 --- /dev/null +++ b/packages/instant/test/util/dependencies/prevbignumber.js @@ -0,0 +1,2705 @@ +/* + * bignumber.js v6.0.0 + * A JavaScript library for arbitrary-precision arithmetic. + * https://github.com/MikeMcl/bignumber.js + * Copyright (c) 2018 Michael Mclaughlin + * MIT Licensed. + * + * BigNumber.prototype methods | BigNumber methods + * | + * absoluteValue abs | clone + * comparedTo | config set + * decimalPlaces dp | DECIMAL_PLACES + * dividedBy div | ROUNDING_MODE + * dividedToIntegerBy idiv | EXPONENTIAL_AT + * exponentiatedBy pow | RANGE + * integerValue | CRYPTO + * isEqualTo eq | MODULO_MODE + * isFinite | POW_PRECISION + * isGreaterThan gt | FORMAT + * isGreaterThanOrEqualTo gte | ALPHABET + * isInteger | isBigNumber + * isLessThan lt | maximum max + * isLessThanOrEqualTo lte | minimum min + * isNaN | random + * isNegative | + * isPositive | + * isZero | + * minus | + * modulo mod | + * multipliedBy times | + * negated | + * plus | + * precision sd | + * shiftedBy | + * squareRoot sqrt | + * toExponential | + * toFixed | + * toFormat | + * toFraction | + * toJSON | + * toNumber | + * toPrecision | + * toString | + * valueOf | + * + */ + + +var BigNumber, + isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i, + + mathceil = Math.ceil, + mathfloor = Math.floor, + + bignumberError = '[BigNumber Error] ', + tooManyDigits = bignumberError + 'Number primitive has more than 15 significant digits: ', + + BASE = 1e14, + LOG_BASE = 14, + MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1 + // MAX_INT32 = 0x7fffffff, // 2^31 - 1 + POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], + SQRT_BASE = 1e7, + + // EDITABLE + // The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and + // the arguments to toExponential, toFixed, toFormat, and toPrecision. + MAX = 1E9; // 0 to MAX_INT32 + + +/* + * Create and return a BigNumber constructor. + */ +function clone(configObject) { + var div, convertBase, parseNumeric, + P = BigNumber.prototype, + ONE = new BigNumber(1), + + + //----------------------------- EDITABLE CONFIG DEFAULTS ------------------------------- + + + // The default values below must be integers within the inclusive ranges stated. + // The values can also be changed at run-time using BigNumber.set. + + // The maximum number of decimal places for operations involving division. + DECIMAL_PLACES = 20, // 0 to MAX + + // The rounding mode used when rounding to the above decimal places, and when using + // toExponential, toFixed, toFormat and toPrecision, and round (default value). + // UP 0 Away from zero. + // DOWN 1 Towards zero. + // CEIL 2 Towards +Infinity. + // FLOOR 3 Towards -Infinity. + // HALF_UP 4 Towards nearest neighbour. If equidistant, up. + // HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. + // HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. + // HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. + // HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. + ROUNDING_MODE = 4, // 0 to 8 + + // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS] + + // The exponent value at and beneath which toString returns exponential notation. + // Number type: -7 + TO_EXP_NEG = -7, // 0 to -MAX + + // The exponent value at and above which toString returns exponential notation. + // Number type: 21 + TO_EXP_POS = 21, // 0 to MAX + + // RANGE : [MIN_EXP, MAX_EXP] + + // The minimum exponent value, beneath which underflow to zero occurs. + // Number type: -324 (5e-324) + MIN_EXP = -1e7, // -1 to -MAX + + // The maximum exponent value, above which overflow to Infinity occurs. + // Number type: 308 (1.7976931348623157e+308) + // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow. + MAX_EXP = 1e7, // 1 to MAX + + // Whether to use cryptographically-secure random number generation, if available. + CRYPTO = false, // true or false + + // The modulo mode used when calculating the modulus: a mod n. + // The quotient (q = a / n) is calculated according to the corresponding rounding mode. + // The remainder (r) is calculated as: r = a - n * q. + // + // UP 0 The remainder is positive if the dividend is negative, else is negative. + // DOWN 1 The remainder has the same sign as the dividend. + // This modulo mode is commonly known as 'truncated division' and is + // equivalent to (a % n) in JavaScript. + // FLOOR 3 The remainder has the same sign as the divisor (Python %). + // HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function. + // EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). + // The remainder is always positive. + // + // The truncated division, floored division, Euclidian division and IEEE 754 remainder + // modes are commonly used for the modulus operation. + // Although the other rounding modes can also be used, they may not give useful results. + MODULO_MODE = 1, // 0 to 9 + + // The maximum number of significant digits of the result of the exponentiatedBy operation. + // If POW_PRECISION is 0, there will be unlimited significant digits. + POW_PRECISION = 0, // 0 to MAX + + // The format specification used by the BigNumber.prototype.toFormat method. + FORMAT = { + decimalSeparator: '.', + groupSeparator: ',', + groupSize: 3, + secondaryGroupSize: 0, + fractionGroupSeparator: '\xA0', // non-breaking space + fractionGroupSize: 0 + }, + + // The alphabet used for base conversion. + // It must be at least 2 characters long, with no '.' or repeated character. + // '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_' + ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'; + + + //------------------------------------------------------------------------------------------ + + + // CONSTRUCTOR + + + /* + * The BigNumber constructor and exported function. + * Create and return a new instance of a BigNumber object. + * + * n {number|string|BigNumber} A numeric value. + * [b] {number} The base of n. Integer, 2 to ALPHABET.length inclusive. + */ + function BigNumber( n, b ) { + var alphabet, c, e, i, isNum, len, str, + x = this; + + // Enable constructor usage without new. + if ( !( x instanceof BigNumber ) ) { + + // Don't throw on constructor call without new (#81). + // '[BigNumber Error] Constructor call without new: {n}' + //throw Error( bignumberError + ' Constructor call without new: ' + n ); + return new BigNumber( n, b ); + } + + if ( b == null ) { + + // Duplicate. + if ( n instanceof BigNumber ) { + x.s = n.s; + x.e = n.e; + x.c = ( n = n.c ) ? n.slice() : n; + return; + } + + isNum = typeof n == 'number'; + + if ( isNum && n * 0 == 0 ) { + + // Use `1 / n` to handle minus zero also. + x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1; + + // Faster path for integers. + if ( n === ~~n ) { + for ( e = 0, i = n; i >= 10; i /= 10, e++ ); + x.e = e; + x.c = [n]; + return; + } + + str = n + ''; + } else { + if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, isNum ); + x.s = str.charCodeAt(0) == 45 ? ( str = str.slice(1), -1 ) : 1; + } + + } else { + + // '[BigNumber Error] Base {not a primitive number|not an integer|out of range}: {b}' + intCheck( b, 2, ALPHABET.length, 'Base' ); + str = n + ''; + + // Allow exponential notation to be used with base 10 argument, while + // also rounding to DECIMAL_PLACES as with other bases. + if ( b == 10 ) { + x = new BigNumber( n instanceof BigNumber ? n : str ); + return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE ); + } + + isNum = typeof n == 'number'; + + if (isNum) { + + // Avoid potential interpretation of Infinity and NaN as base 44+ values. + if ( n * 0 != 0 ) return parseNumeric( x, str, isNum, b ); + + x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1; + + // '[BigNumber Error] Number primitive has more than 15 significant digits: {n}' + if ( str.replace( /^0\.0*|\./, '' ).length > 15 ) { + throw Error + ( tooManyDigits + n ); + } + + // Prevent later check for length on converted number. + isNum = false; + } else { + x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; + + // Allow e.g. hexadecimal 'FF' as well as 'ff'. + if ( b > 10 && b < 37 ) str = str.toLowerCase(); + } + + alphabet = ALPHABET.slice( 0, b ); + e = i = 0; + + // Check that str is a valid base b number. + // Don't use RegExp so alphabet can contain special characters. + for ( len = str.length; i < len; i++ ) { + if ( alphabet.indexOf( c = str.charAt(i) ) < 0 ) { + if ( c == '.' ) { + + // If '.' is not the first character and it has not be found before. + if ( i > e ) { + e = len; + continue; + } + } + + return parseNumeric( x, n + '', isNum, b ); + } + } + + str = convertBase( str, b, 10, x.s ); + } + + // Decimal point? + if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' ); + + // Exponential form? + if ( ( i = str.search( /e/i ) ) > 0 ) { + + // Determine exponent. + if ( e < 0 ) e = i; + e += +str.slice( i + 1 ); + str = str.substring( 0, i ); + } else if ( e < 0 ) { + + // Integer. + e = str.length; + } + + // Determine leading zeros. + for ( i = 0; str.charCodeAt(i) === 48; i++ ); + + // Determine trailing zeros. + for ( len = str.length; str.charCodeAt(--len) === 48; ); + str = str.slice( i, len + 1 ); + + if (str) { + len = str.length; + + // '[BigNumber Error] Number primitive has more than 15 significant digits: {n}' + if ( isNum && len > 15 && ( n > MAX_SAFE_INTEGER || n !== mathfloor(n) ) ) { + throw Error + ( tooManyDigits + ( x.s * n ) ); + } + + e = e - i - 1; + + // Overflow? + if ( e > MAX_EXP ) { + + // Infinity. + x.c = x.e = null; + + // Underflow? + } else if ( e < MIN_EXP ) { + + // Zero. + x.c = [ x.e = 0 ]; + } else { + x.e = e; + x.c = []; + + // Transform base + + // e is the base 10 exponent. + // i is where to slice str to get the first element of the coefficient array. + i = ( e + 1 ) % LOG_BASE; + if ( e < 0 ) i += LOG_BASE; + + if ( i < len ) { + if (i) x.c.push( +str.slice( 0, i ) ); + + for ( len -= LOG_BASE; i < len; ) { + x.c.push( +str.slice( i, i += LOG_BASE ) ); + } + + str = str.slice(i); + i = LOG_BASE - str.length; + } else { + i -= len; + } + + for ( ; i--; str += '0' ); + x.c.push( +str ); + } + } else { + + // Zero. + x.c = [ x.e = 0 ]; + } + } + + + // CONSTRUCTOR PROPERTIES + + + BigNumber.clone = clone; + + BigNumber.ROUND_UP = 0; + BigNumber.ROUND_DOWN = 1; + BigNumber.ROUND_CEIL = 2; + BigNumber.ROUND_FLOOR = 3; + BigNumber.ROUND_HALF_UP = 4; + BigNumber.ROUND_HALF_DOWN = 5; + BigNumber.ROUND_HALF_EVEN = 6; + BigNumber.ROUND_HALF_CEIL = 7; + BigNumber.ROUND_HALF_FLOOR = 8; + BigNumber.EUCLID = 9; + + + /* + * Configure infrequently-changing library-wide settings. + * + * Accept an object with the following optional properties (if the value of a property is + * a number, it must be an integer within the inclusive range stated): + * + * DECIMAL_PLACES {number} 0 to MAX + * ROUNDING_MODE {number} 0 to 8 + * EXPONENTIAL_AT {number|number[]} -MAX to MAX or [-MAX to 0, 0 to MAX] + * RANGE {number|number[]} -MAX to MAX (not zero) or [-MAX to -1, 1 to MAX] + * CRYPTO {boolean} true or false + * MODULO_MODE {number} 0 to 9 + * POW_PRECISION {number} 0 to MAX + * ALPHABET {string} A string of two or more unique characters, and not + * containing '.'. The empty string, null or undefined + * resets the alphabet to its default value. + * FORMAT {object} An object with some of the following properties: + * decimalSeparator {string} + * groupSeparator {string} + * groupSize {number} + * secondaryGroupSize {number} + * fractionGroupSeparator {string} + * fractionGroupSize {number} + * + * (The values assigned to the above FORMAT object properties are not checked for validity.) + * + * E.g. + * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 }) + * + * Ignore properties/parameters set to null or undefined, except for ALPHABET. + * + * Return an object with the properties current values. + */ + BigNumber.config = BigNumber.set = function (obj) { + var p, v; + + if ( obj != null ) { + + if ( typeof obj == 'object' ) { + + // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive. + // '[BigNumber Error] DECIMAL_PLACES {not a primitive number|not an integer|out of range}: {v}' + if ( obj.hasOwnProperty( p = 'DECIMAL_PLACES' ) ) { + v = obj[p]; + intCheck( v, 0, MAX, p ); + DECIMAL_PLACES = v; + } + + // ROUNDING_MODE {number} Integer, 0 to 8 inclusive. + // '[BigNumber Error] ROUNDING_MODE {not a primitive number|not an integer|out of range}: {v}' + if ( obj.hasOwnProperty( p = 'ROUNDING_MODE' ) ) { + v = obj[p]; + intCheck( v, 0, 8, p ); + ROUNDING_MODE = v; + } + + // EXPONENTIAL_AT {number|number[]} + // Integer, -MAX to MAX inclusive or + // [integer -MAX to 0 inclusive, 0 to MAX inclusive]. + // '[BigNumber Error] EXPONENTIAL_AT {not a primitive number|not an integer|out of range}: {v}' + if ( obj.hasOwnProperty( p = 'EXPONENTIAL_AT' ) ) { + v = obj[p]; + if ( isArray(v) ) { + intCheck( v[0], -MAX, 0, p ); + intCheck( v[1], 0, MAX, p ); + TO_EXP_NEG = v[0]; + TO_EXP_POS = v[1]; + } else { + intCheck( v, -MAX, MAX, p ); + TO_EXP_NEG = -( TO_EXP_POS = v < 0 ? -v : v ); + } + } + + // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or + // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive]. + // '[BigNumber Error] RANGE {not a primitive number|not an integer|out of range|cannot be zero}: {v}' + if ( obj.hasOwnProperty( p = 'RANGE' ) ) { + v = obj[p]; + if ( isArray(v) ) { + intCheck( v[0], -MAX, -1, p ); + intCheck( v[1], 1, MAX, p ); + MIN_EXP = v[0]; + MAX_EXP = v[1]; + } else { + intCheck( v, -MAX, MAX, p ); + if (v) { + MIN_EXP = -( MAX_EXP = v < 0 ? -v : v ); + } else { + throw Error + ( bignumberError + p + ' cannot be zero: ' + v ); + } + } + } + + // CRYPTO {boolean} true or false. + // '[BigNumber Error] CRYPTO not true or false: {v}' + // '[BigNumber Error] crypto unavailable' + if ( obj.hasOwnProperty( p = 'CRYPTO' ) ) { + v = obj[p]; + if ( v === !!v ) { + if (v) { + if ( typeof crypto != 'undefined' && crypto && + (crypto.getRandomValues || crypto.randomBytes) ) { + CRYPTO = v; + } else { + CRYPTO = !v; + throw Error + ( bignumberError + 'crypto unavailable' ); + } + } else { + CRYPTO = v; + } + } else { + throw Error + ( bignumberError + p + ' not true or false: ' + v ); + } + } + + // MODULO_MODE {number} Integer, 0 to 9 inclusive. + // '[BigNumber Error] MODULO_MODE {not a primitive number|not an integer|out of range}: {v}' + if ( obj.hasOwnProperty( p = 'MODULO_MODE' ) ) { + v = obj[p]; + intCheck( v, 0, 9, p ); + MODULO_MODE = v; + } + + // POW_PRECISION {number} Integer, 0 to MAX inclusive. + // '[BigNumber Error] POW_PRECISION {not a primitive number|not an integer|out of range}: {v}' + if ( obj.hasOwnProperty( p = 'POW_PRECISION' ) ) { + v = obj[p]; + intCheck( v, 0, MAX, p ); + POW_PRECISION = v; + } + + // FORMAT {object} + // '[BigNumber Error] FORMAT not an object: {v}' + if ( obj.hasOwnProperty( p = 'FORMAT' ) ) { + v = obj[p]; + if ( typeof v == 'object' ) FORMAT = v; + else throw Error + ( bignumberError + p + ' not an object: ' + v ); + } + + // ALPHABET {string} + // '[BigNumber Error] ALPHABET invalid: {v}' + if ( obj.hasOwnProperty( p = 'ALPHABET' ) ) { + v = obj[p]; + + // Disallow if only one character, or contains '.' or a repeated character. + if ( typeof v == 'string' && !/^.$|\.|(.).*\1/.test(v) ) { + ALPHABET = v; + } else { + throw Error + ( bignumberError + p + ' invalid: ' + v ); + } + } + + } else { + + // '[BigNumber Error] Object expected: {v}' + throw Error + ( bignumberError + 'Object expected: ' + obj ); + } + } + + return { + DECIMAL_PLACES: DECIMAL_PLACES, + ROUNDING_MODE: ROUNDING_MODE, + EXPONENTIAL_AT: [ TO_EXP_NEG, TO_EXP_POS ], + RANGE: [ MIN_EXP, MAX_EXP ], + CRYPTO: CRYPTO, + MODULO_MODE: MODULO_MODE, + POW_PRECISION: POW_PRECISION, + FORMAT: FORMAT, + ALPHABET: ALPHABET + }; + }; + + + /* + * Return true if v is a BigNumber instance, otherwise return false. + * + * v {any} + */ + BigNumber.isBigNumber = function (v) { + return v instanceof BigNumber || v && v._isBigNumber === true || false; + }; + + + /* + * Return a new BigNumber whose value is the maximum of the arguments. + * + * arguments {number|string|BigNumber} + */ + BigNumber.maximum = BigNumber.max = function () { + return maxOrMin( arguments, P.lt ); + }; + + + /* + * Return a new BigNumber whose value is the minimum of the arguments. + * + * arguments {number|string|BigNumber} + */ + BigNumber.minimum = BigNumber.min = function () { + return maxOrMin( arguments, P.gt ); + }; + + + /* + * Return a new BigNumber with a random value equal to or greater than 0 and less than 1, + * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing + * zeros are produced). + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp}' + * '[BigNumber Error] crypto unavailable' + */ + BigNumber.random = (function () { + var pow2_53 = 0x20000000000000; + + // Return a 53 bit integer n, where 0 <= n < 9007199254740992. + // Check if Math.random() produces more than 32 bits of randomness. + // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits. + // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1. + var random53bitInt = (Math.random() * pow2_53) & 0x1fffff + ? function () { return mathfloor( Math.random() * pow2_53 ); } + : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) + + (Math.random() * 0x800000 | 0); }; + + return function (dp) { + var a, b, e, k, v, + i = 0, + c = [], + rand = new BigNumber(ONE); + + if ( dp == null ) dp = DECIMAL_PLACES; + else intCheck( dp, 0, MAX ); + + k = mathceil( dp / LOG_BASE ); + + if (CRYPTO) { + + // Browsers supporting crypto.getRandomValues. + if (crypto.getRandomValues) { + + a = crypto.getRandomValues( new Uint32Array( k *= 2 ) ); + + for ( ; i < k; ) { + + // 53 bits: + // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2) + // 11111 11111111 11111111 11111111 11100000 00000000 00000000 + // ((Math.pow(2, 32) - 1) >>> 11).toString(2) + // 11111 11111111 11111111 + // 0x20000 is 2^21. + v = a[i] * 0x20000 + (a[i + 1] >>> 11); + + // Rejection sampling: + // 0 <= v < 9007199254740992 + // Probability that v >= 9e15, is + // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251 + if ( v >= 9e15 ) { + b = crypto.getRandomValues( new Uint32Array(2) ); + a[i] = b[0]; + a[i + 1] = b[1]; + } else { + + // 0 <= v <= 8999999999999999 + // 0 <= (v % 1e14) <= 99999999999999 + c.push( v % 1e14 ); + i += 2; + } + } + i = k / 2; + + // Node.js supporting crypto.randomBytes. + } else if (crypto.randomBytes) { + + // buffer + a = crypto.randomBytes( k *= 7 ); + + for ( ; i < k; ) { + + // 0x1000000000000 is 2^48, 0x10000000000 is 2^40 + // 0x100000000 is 2^32, 0x1000000 is 2^24 + // 11111 11111111 11111111 11111111 11111111 11111111 11111111 + // 0 <= v < 9007199254740992 + v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) + + ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) + + ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6]; + + if ( v >= 9e15 ) { + crypto.randomBytes(7).copy( a, i ); + } else { + + // 0 <= (v % 1e14) <= 99999999999999 + c.push( v % 1e14 ); + i += 7; + } + } + i = k / 7; + } else { + CRYPTO = false; + throw Error + ( bignumberError + 'crypto unavailable' ); + } + } + + // Use Math.random. + if (!CRYPTO) { + + for ( ; i < k; ) { + v = random53bitInt(); + if ( v < 9e15 ) c[i++] = v % 1e14; + } + } + + k = c[--i]; + dp %= LOG_BASE; + + // Convert trailing digits to zeros according to dp. + if ( k && dp ) { + v = POWS_TEN[LOG_BASE - dp]; + c[i] = mathfloor( k / v ) * v; + } + + // Remove trailing elements which are zero. + for ( ; c[i] === 0; c.pop(), i-- ); + + // Zero? + if ( i < 0 ) { + c = [ e = 0 ]; + } else { + + // Remove leading elements which are zero and adjust exponent accordingly. + for ( e = -1 ; c[0] === 0; c.splice(0, 1), e -= LOG_BASE); + + // Count the digits of the first element of c to determine leading zeros, and... + for ( i = 1, v = c[0]; v >= 10; v /= 10, i++); + + // adjust the exponent accordingly. + if ( i < LOG_BASE ) e -= LOG_BASE - i; + } + + rand.e = e; + rand.c = c; + return rand; + }; + })(); + + + // PRIVATE FUNCTIONS + + + // Called by BigNumber and BigNumber.prototype.toString. + convertBase = ( function () { + var decimal = '0123456789'; + + /* + * Convert string of baseIn to an array of numbers of baseOut. + * Eg. toBaseOut('255', 10, 16) returns [15, 15]. + * Eg. toBaseOut('ff', 16, 10) returns [2, 5, 5]. + */ + function toBaseOut( str, baseIn, baseOut, alphabet ) { + var j, + arr = [0], + arrL, + i = 0, + len = str.length; + + for ( ; i < len; ) { + for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn ); + + arr[0] += alphabet.indexOf( str.charAt( i++ ) ); + + for ( j = 0; j < arr.length; j++ ) { + + if ( arr[j] > baseOut - 1 ) { + if ( arr[j + 1] == null ) arr[j + 1] = 0; + arr[j + 1] += arr[j] / baseOut | 0; + arr[j] %= baseOut; + } + } + } + + return arr.reverse(); + } + + // Convert a numeric string of baseIn to a numeric string of baseOut. + // If the caller is toString, we are converting from base 10 to baseOut. + // If the caller is BigNumber, we are converting from baseIn to base 10. + return function ( str, baseIn, baseOut, sign, callerIsToString ) { + var alphabet, d, e, k, r, x, xc, y, + i = str.indexOf( '.' ), + dp = DECIMAL_PLACES, + rm = ROUNDING_MODE; + + // Non-integer. + if ( i >= 0 ) { + k = POW_PRECISION; + + // Unlimited precision. + POW_PRECISION = 0; + str = str.replace( '.', '' ); + y = new BigNumber(baseIn); + x = y.pow( str.length - i ); + POW_PRECISION = k; + + // Convert str as if an integer, then restore the fraction part by dividing the + // result by its base raised to a power. + + y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e, '0' ), + 10, baseOut, decimal ); + y.e = y.c.length; + } + + // Convert the number as integer. + + xc = toBaseOut( str, baseIn, baseOut, callerIsToString + ? ( alphabet = ALPHABET, decimal ) + : ( alphabet = decimal, ALPHABET ) ); + + + // xc now represents str as an integer and converted to baseOut. e is the exponent. + e = k = xc.length; + + // Remove trailing zeros. + for ( ; xc[--k] == 0; xc.pop() ); + + // Zero? + if ( !xc[0] ) return alphabet.charAt(0); + + // Does str represent an integer? If so, no need for the division. + if ( i < 0 ) { + --e; + } else { + x.c = xc; + x.e = e; + + // The sign is needed for correct rounding. + x.s = sign; + x = div( x, y, dp, rm, baseOut ); + xc = x.c; + r = x.r; + e = x.e; + } + + // xc now represents str converted to baseOut. + + // THe index of the rounding digit. + d = e + dp + 1; + + // The rounding digit: the digit to the right of the digit that may be rounded up. + i = xc[d]; + + // Look at the rounding digits and mode to determine whether to round up. + + k = baseOut / 2; + r = r || d < 0 || xc[d + 1] != null; + + r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) + : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 || + rm == ( x.s < 0 ? 8 : 7 ) ); + + // If the index of the rounding digit is not greater than zero, or xc represents + // zero, then the result of the base conversion is zero or, if rounding up, a value + // such as 0.00001. + if ( d < 1 || !xc[0] ) { + + // 1^-dp or 0 + str = r ? toFixedPoint( alphabet.charAt(1), -dp, alphabet.charAt(0) ) + : alphabet.charAt(0); + } else { + + // Truncate xc to the required number of decimal places. + xc.length = d; + + // Round up? + if (r) { + + // Rounding up may mean the previous digit has to be rounded up and so on. + for ( --baseOut; ++xc[--d] > baseOut; ) { + xc[d] = 0; + + if ( !d ) { + ++e; + xc = [1].concat(xc); + } + } + } + + // Determine trailing zeros. + for ( k = xc.length; !xc[--k]; ); + + // E.g. [4, 11, 15] becomes 4bf. + for ( i = 0, str = ''; i <= k; str += alphabet.charAt( xc[i++] ) ); + + // Add leading zeros, decimal point and trailing zeros as required. + str = toFixedPoint( str, e, alphabet.charAt(0) ); + } + + // The caller will add the sign. + return str; + }; + })(); + + + // Perform division in the specified base. Called by div and convertBase. + div = (function () { + + // Assume non-zero x and k. + function multiply( x, k, base ) { + var m, temp, xlo, xhi, + carry = 0, + i = x.length, + klo = k % SQRT_BASE, + khi = k / SQRT_BASE | 0; + + for ( x = x.slice(); i--; ) { + xlo = x[i] % SQRT_BASE; + xhi = x[i] / SQRT_BASE | 0; + m = khi * xlo + xhi * klo; + temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry; + carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi; + x[i] = temp % base; + } + + if (carry) x = [carry].concat(x); + + return x; + } + + function compare( a, b, aL, bL ) { + var i, cmp; + + if ( aL != bL ) { + cmp = aL > bL ? 1 : -1; + } else { + + for ( i = cmp = 0; i < aL; i++ ) { + + if ( a[i] != b[i] ) { + cmp = a[i] > b[i] ? 1 : -1; + break; + } + } + } + return cmp; + } + + function subtract( a, b, aL, base ) { + var i = 0; + + // Subtract b from a. + for ( ; aL--; ) { + a[aL] -= i; + i = a[aL] < b[aL] ? 1 : 0; + a[aL] = i * base + a[aL] - b[aL]; + } + + // Remove leading zeros. + for ( ; !a[0] && a.length > 1; a.splice(0, 1) ); + } + + // x: dividend, y: divisor. + return function ( x, y, dp, rm, base ) { + var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0, + yL, yz, + s = x.s == y.s ? 1 : -1, + xc = x.c, + yc = y.c; + + // Either NaN, Infinity or 0? + if ( !xc || !xc[0] || !yc || !yc[0] ) { + + return new BigNumber( + + // Return NaN if either NaN, or both Infinity or 0. + !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN : + + // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0. + xc && xc[0] == 0 || !yc ? s * 0 : s / 0 + ); + } + + q = new BigNumber(s); + qc = q.c = []; + e = x.e - y.e; + s = dp + e + 1; + + if ( !base ) { + base = BASE; + e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE ); + s = s / LOG_BASE | 0; + } + + // Result exponent may be one less then the current value of e. + // The coefficients of the BigNumbers from convertBase may have trailing zeros. + for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ ); + + if ( yc[i] > ( xc[i] || 0 ) ) e--; + + if ( s < 0 ) { + qc.push(1); + more = true; + } else { + xL = xc.length; + yL = yc.length; + i = 0; + s += 2; + + // Normalise xc and yc so highest order digit of yc is >= base / 2. + + n = mathfloor( base / ( yc[0] + 1 ) ); + + // Not necessary, but to handle odd bases where yc[0] == ( base / 2 ) - 1. + // if ( n > 1 || n++ == 1 && yc[0] < base / 2 ) { + if ( n > 1 ) { + yc = multiply( yc, n, base ); + xc = multiply( xc, n, base ); + yL = yc.length; + xL = xc.length; + } + + xi = yL; + rem = xc.slice( 0, yL ); + remL = rem.length; + + // Add zeros to make remainder as long as divisor. + for ( ; remL < yL; rem[remL++] = 0 ); + yz = yc.slice(); + yz = [0].concat(yz); + yc0 = yc[0]; + if ( yc[1] >= base / 2 ) yc0++; + // Not necessary, but to prevent trial digit n > base, when using base 3. + // else if ( base == 3 && yc0 == 1 ) yc0 = 1 + 1e-15; + + do { + n = 0; + + // Compare divisor and remainder. + cmp = compare( yc, rem, yL, remL ); + + // If divisor < remainder. + if ( cmp < 0 ) { + + // Calculate trial digit, n. + + rem0 = rem[0]; + if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 ); + + // n is how many times the divisor goes into the current remainder. + n = mathfloor( rem0 / yc0 ); + + // Algorithm: + // 1. product = divisor * trial digit (n) + // 2. if product > remainder: product -= divisor, n-- + // 3. remainder -= product + // 4. if product was < remainder at 2: + // 5. compare new remainder and divisor + // 6. If remainder > divisor: remainder -= divisor, n++ + + if ( n > 1 ) { + + // n may be > base only when base is 3. + if (n >= base) n = base - 1; + + // product = divisor * trial digit. + prod = multiply( yc, n, base ); + prodL = prod.length; + remL = rem.length; + + // Compare product and remainder. + // If product > remainder. + // Trial digit n too high. + // n is 1 too high about 5% of the time, and is not known to have + // ever been more than 1 too high. + while ( compare( prod, rem, prodL, remL ) == 1 ) { + n--; + + // Subtract divisor from product. + subtract( prod, yL < prodL ? yz : yc, prodL, base ); + prodL = prod.length; + cmp = 1; + } + } else { + + // n is 0 or 1, cmp is -1. + // If n is 0, there is no need to compare yc and rem again below, + // so change cmp to 1 to avoid it. + // If n is 1, leave cmp as -1, so yc and rem are compared again. + if ( n == 0 ) { + + // divisor < remainder, so n must be at least 1. + cmp = n = 1; + } + + // product = divisor + prod = yc.slice(); + prodL = prod.length; + } + + if ( prodL < remL ) prod = [0].concat(prod); + + // Subtract product from remainder. + subtract( rem, prod, remL, base ); + remL = rem.length; + + // If product was < remainder. + if ( cmp == -1 ) { + + // Compare divisor and new remainder. + // If divisor < new remainder, subtract divisor from remainder. + // Trial digit n too low. + // n is 1 too low about 5% of the time, and very rarely 2 too low. + while ( compare( yc, rem, yL, remL ) < 1 ) { + n++; + + // Subtract divisor from remainder. + subtract( rem, yL < remL ? yz : yc, remL, base ); + remL = rem.length; + } + } + } else if ( cmp === 0 ) { + n++; + rem = [0]; + } // else cmp === 1 and n will be 0 + + // Add the next digit, n, to the result array. + qc[i++] = n; + + // Update the remainder. + if ( rem[0] ) { + rem[remL++] = xc[xi] || 0; + } else { + rem = [ xc[xi] ]; + remL = 1; + } + } while ( ( xi++ < xL || rem[0] != null ) && s-- ); + + more = rem[0] != null; + + // Leading zero? + if ( !qc[0] ) qc.splice(0, 1); + } + + if ( base == BASE ) { + + // To calculate q.e, first get the number of digits of qc[0]. + for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ ); + + round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more ); + + // Caller is convertBase. + } else { + q.e = e; + q.r = +more; + } + + return q; + }; + })(); + + + /* + * Return a string representing the value of BigNumber n in fixed-point or exponential + * notation rounded to the specified decimal places or significant digits. + * + * n: a BigNumber. + * i: the index of the last digit required (i.e. the digit that may be rounded up). + * rm: the rounding mode. + * id: 1 (toExponential) or 2 (toPrecision). + */ + function format( n, i, rm, id ) { + var c0, e, ne, len, str; + + if ( rm == null ) rm = ROUNDING_MODE; + else intCheck( rm, 0, 8 ); + + if ( !n.c ) return n.toString(); + + c0 = n.c[0]; + ne = n.e; + + if ( i == null ) { + str = coeffToString( n.c ); + str = id == 1 || id == 2 && ne <= TO_EXP_NEG + ? toExponential( str, ne ) + : toFixedPoint( str, ne, '0' ); + } else { + n = round( new BigNumber(n), i, rm ); + + // n.e may have changed if the value was rounded up. + e = n.e; + + str = coeffToString( n.c ); + len = str.length; + + // toPrecision returns exponential notation if the number of significant digits + // specified is less than the number of digits necessary to represent the integer + // part of the value in fixed-point notation. + + // Exponential notation. + if ( id == 1 || id == 2 && ( i <= e || e <= TO_EXP_NEG ) ) { + + // Append zeros? + for ( ; len < i; str += '0', len++ ); + str = toExponential( str, e ); + + // Fixed-point notation. + } else { + i -= ne; + str = toFixedPoint( str, e, '0' ); + + // Append zeros? + if ( e + 1 > len ) { + if ( --i > 0 ) for ( str += '.'; i--; str += '0' ); + } else { + i += e - len; + if ( i > 0 ) { + if ( e + 1 == len ) str += '.'; + for ( ; i--; str += '0' ); + } + } + } + } + + return n.s < 0 && c0 ? '-' + str : str; + } + + + // Handle BigNumber.max and BigNumber.min. + function maxOrMin( args, method ) { + var m, n, + i = 0; + + if ( isArray( args[0] ) ) args = args[0]; + m = new BigNumber( args[0] ); + + for ( ; ++i < args.length; ) { + n = new BigNumber( args[i] ); + + // If any number is NaN, return NaN. + if ( !n.s ) { + m = n; + break; + } else if ( method.call( m, n ) ) { + m = n; + } + } + + return m; + } + + + /* + * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP. + * Called by minus, plus and times. + */ + function normalise( n, c, e ) { + var i = 1, + j = c.length; + + // Remove trailing zeros. + for ( ; !c[--j]; c.pop() ); + + // Calculate the base 10 exponent. First get the number of digits of c[0]. + for ( j = c[0]; j >= 10; j /= 10, i++ ); + + // Overflow? + if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) { + + // Infinity. + n.c = n.e = null; + + // Underflow? + } else if ( e < MIN_EXP ) { + + // Zero. + n.c = [ n.e = 0 ]; + } else { + n.e = e; + n.c = c; + } + + return n; + } + + + // Handle values that fail the validity test in BigNumber. + parseNumeric = (function () { + var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, + dotAfter = /^([^.]+)\.$/, + dotBefore = /^\.([^.]+)$/, + isInfinityOrNaN = /^-?(Infinity|NaN)$/, + whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g; + + return function ( x, str, isNum, b ) { + var base, + s = isNum ? str : str.replace( whitespaceOrPlus, '' ); + + // No exception on ±Infinity or NaN. + if ( isInfinityOrNaN.test(s) ) { + x.s = isNaN(s) ? null : s < 0 ? -1 : 1; + x.c = x.e = null; + } else { + if ( !isNum ) { + + // basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i + s = s.replace( basePrefix, function ( m, p1, p2 ) { + base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8; + return !b || b == base ? p1 : m; + }); + + if (b) { + base = b; + + // E.g. '1.' to '1', '.1' to '0.1' + s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' ); + } + + if ( str != s ) return new BigNumber( s, base ); + } + + // '[BigNumber Error] Not a number: {n}' + // '[BigNumber Error] Not a base {b} number: {n}' + throw Error + ( bignumberError + 'Not a' + ( b ? ' base ' + b : '' ) + ' number: ' + str ); + } + } + })(); + + + /* + * Round x to sd significant digits using rounding mode rm. Check for over/under-flow. + * If r is truthy, it is known that there are more digits after the rounding digit. + */ + function round( x, sd, rm, r ) { + var d, i, j, k, n, ni, rd, + xc = x.c, + pows10 = POWS_TEN; + + // if x is not Infinity or NaN... + if (xc) { + + // rd is the rounding digit, i.e. the digit after the digit that may be rounded up. + // n is a base 1e14 number, the value of the element of array x.c containing rd. + // ni is the index of n within x.c. + // d is the number of digits of n. + // i is the index of rd within n including leading zeros. + // j is the actual index of rd within n (if < 0, rd is a leading zero). + out: { + + // Get the number of digits of the first element of xc. + for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ ); + i = sd - d; + + // If the rounding digit is in the first element of xc... + if ( i < 0 ) { + i += LOG_BASE; + j = sd; + n = xc[ ni = 0 ]; + + // Get the rounding digit at index j of n. + rd = n / pows10[ d - j - 1 ] % 10 | 0; + } else { + ni = mathceil( ( i + 1 ) / LOG_BASE ); + + if ( ni >= xc.length ) { + + if (r) { + + // Needed by sqrt. + for ( ; xc.length <= ni; xc.push(0) ); + n = rd = 0; + d = 1; + i %= LOG_BASE; + j = i - LOG_BASE + 1; + } else { + break out; + } + } else { + n = k = xc[ni]; + + // Get the number of digits of n. + for ( d = 1; k >= 10; k /= 10, d++ ); + + // Get the index of rd within n. + i %= LOG_BASE; + + // Get the index of rd within n, adjusted for leading zeros. + // The number of leading zeros of n is given by LOG_BASE - d. + j = i - LOG_BASE + d; + + // Get the rounding digit at index j of n. + rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0; + } + } + + r = r || sd < 0 || + + // Are there any non-zero digits after the rounding digit? + // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right + // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714. + xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] ); + + r = rm < 4 + ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) + : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 && + + // Check whether the digit to the left of the rounding digit is odd. + ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 || + rm == ( x.s < 0 ? 8 : 7 ) ); + + if ( sd < 1 || !xc[0] ) { + xc.length = 0; + + if (r) { + + // Convert sd to decimal places. + sd -= x.e + 1; + + // 1, 0.1, 0.01, 0.001, 0.0001 etc. + xc[0] = pows10[ ( LOG_BASE - sd % LOG_BASE ) % LOG_BASE ]; + x.e = -sd || 0; + } else { + + // Zero. + xc[0] = x.e = 0; + } + + return x; + } + + // Remove excess digits. + if ( i == 0 ) { + xc.length = ni; + k = 1; + ni--; + } else { + xc.length = ni + 1; + k = pows10[ LOG_BASE - i ]; + + // E.g. 56700 becomes 56000 if 7 is the rounding digit. + // j > 0 means i > number of leading zeros of n. + xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0; + } + + // Round up? + if (r) { + + for ( ; ; ) { + + // If the digit to be rounded up is in the first element of xc... + if ( ni == 0 ) { + + // i will be the length of xc[0] before k is added. + for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ ); + j = xc[0] += k; + for ( k = 1; j >= 10; j /= 10, k++ ); + + // if i != k the length has increased. + if ( i != k ) { + x.e++; + if ( xc[0] == BASE ) xc[0] = 1; + } + + break; + } else { + xc[ni] += k; + if ( xc[ni] != BASE ) break; + xc[ni--] = 0; + k = 1; + } + } + } + + // Remove trailing zeros. + for ( i = xc.length; xc[--i] === 0; xc.pop() ); + } + + // Overflow? Infinity. + if ( x.e > MAX_EXP ) { + x.c = x.e = null; + + // Underflow? Zero. + } else if ( x.e < MIN_EXP ) { + x.c = [ x.e = 0 ]; + } + } + + return x; + } + + + // PROTOTYPE/INSTANCE METHODS + + + /* + * Return a new BigNumber whose value is the absolute value of this BigNumber. + */ + P.absoluteValue = P.abs = function () { + var x = new BigNumber(this); + if ( x.s < 0 ) x.s = 1; + return x; + }; + + + /* + * Return + * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b), + * -1 if the value of this BigNumber is less than the value of BigNumber(y, b), + * 0 if they have the same value, + * or null if the value of either is NaN. + */ + P.comparedTo = function ( y, b ) { + return compare( this, new BigNumber( y, b ) ); + }; + + + /* + * If dp is undefined or null or true or false, return the number of decimal places of the + * value of this BigNumber, or null if the value of this BigNumber is ±Infinity or NaN. + * + * Otherwise, if dp is a number, return a new BigNumber whose value is the value of this + * BigNumber rounded to a maximum of dp decimal places using rounding mode rm, or + * ROUNDING_MODE if rm is omitted. + * + * [dp] {number} Decimal places: integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' + */ + P.decimalPlaces = P.dp = function ( dp, rm ) { + var c, n, v, + x = this; + + if ( dp != null ) { + intCheck( dp, 0, MAX ); + if ( rm == null ) rm = ROUNDING_MODE; + else intCheck( rm, 0, 8 ); + + return round( new BigNumber(x), dp + x.e + 1, rm ); + } + + if ( !( c = x.c ) ) return null; + n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE; + + // Subtract the number of trailing zeros of the last number. + if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- ); + if ( n < 0 ) n = 0; + + return n; + }; + + + /* + * n / 0 = I + * n / N = N + * n / I = 0 + * 0 / n = 0 + * 0 / 0 = N + * 0 / N = N + * 0 / I = 0 + * N / n = N + * N / 0 = N + * N / N = N + * N / I = N + * I / n = I + * I / 0 = I + * I / N = N + * I / I = N + * + * Return a new BigNumber whose value is the value of this BigNumber divided by the value of + * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE. + */ + P.dividedBy = P.div = function ( y, b ) { + return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE ); + }; + + + /* + * Return a new BigNumber whose value is the integer part of dividing the value of this + * BigNumber by the value of BigNumber(y, b). + */ + P.dividedToIntegerBy = P.idiv = function ( y, b ) { + return div( this, new BigNumber( y, b ), 0, 1 ); + }; + + + /* + * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b), + * otherwise return false. + */ + P.isEqualTo = P.eq = function ( y, b ) { + return compare( this, new BigNumber( y, b ) ) === 0; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to an integer + * using rounding mode rm, or ROUNDING_MODE if rm is omitted. + * + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {rm}' + */ + P.integerValue = function (rm) { + var n = new BigNumber(this); + if ( rm == null ) rm = ROUNDING_MODE; + else intCheck( rm, 0, 8 ); + return round( n, n.e + 1, rm ); + }; + + + /* + * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b), + * otherwise return false. + */ + P.isGreaterThan = P.gt = function ( y, b ) { + return compare( this, new BigNumber( y, b ) ) > 0; + }; + + + /* + * Return true if the value of this BigNumber is greater than or equal to the value of + * BigNumber(y, b), otherwise return false. + */ + P.isGreaterThanOrEqualTo = P.gte = function ( y, b ) { + return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0; + + }; + + + /* + * Return true if the value of this BigNumber is a finite number, otherwise return false. + */ + P.isFinite = function () { + return !!this.c; + }; + + + /* + * Return true if the value of this BigNumber is an integer, otherwise return false. + */ + P.isInteger = function () { + return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2; + }; + + + /* + * Return true if the value of this BigNumber is NaN, otherwise return false. + */ + P.isNaN = function () { + return !this.s; + }; + + + /* + * Return true if the value of this BigNumber is negative, otherwise return false. + */ + P.isNegative = function () { + return this.s < 0; + }; + + + /* + * Return true if the value of this BigNumber is positive, otherwise return false. + */ + P.isPositive = function () { + return this.s > 0; + }; + + + /* + * Return true if the value of this BigNumber is 0 or -0, otherwise return false. + */ + P.isZero = function () { + return !!this.c && this.c[0] == 0; + }; + + + /* + * Return true if the value of this BigNumber is less than the value of BigNumber(y, b), + * otherwise return false. + */ + P.isLessThan = P.lt = function ( y, b ) { + return compare( this, new BigNumber( y, b ) ) < 0; + }; + + + /* + * Return true if the value of this BigNumber is less than or equal to the value of + * BigNumber(y, b), otherwise return false. + */ + P.isLessThanOrEqualTo = P.lte = function ( y, b ) { + return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0; + }; + + + /* + * n - 0 = n + * n - N = N + * n - I = -I + * 0 - n = -n + * 0 - 0 = 0 + * 0 - N = N + * 0 - I = -I + * N - n = N + * N - 0 = N + * N - N = N + * N - I = N + * I - n = I + * I - 0 = I + * I - N = N + * I - I = N + * + * Return a new BigNumber whose value is the value of this BigNumber minus the value of + * BigNumber(y, b). + */ + P.minus = function ( y, b ) { + var i, j, t, xLTy, + x = this, + a = x.s; + + y = new BigNumber( y, b ); + b = y.s; + + // Either NaN? + if ( !a || !b ) return new BigNumber(NaN); + + // Signs differ? + if ( a != b ) { + y.s = -b; + return x.plus(y); + } + + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + + if ( !xe || !ye ) { + + // Either Infinity? + if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN ); + + // Either zero? + if ( !xc[0] || !yc[0] ) { + + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. + return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x : + + // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity + ROUNDING_MODE == 3 ? -0 : 0 ); + } + } + + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + + // Determine which is the bigger number. + if ( a = xe - ye ) { + + if ( xLTy = a < 0 ) { + a = -a; + t = xc; + } else { + ye = xe; + t = yc; + } + + t.reverse(); + + // Prepend zeros to equalise exponents. + for ( b = a; b--; t.push(0) ); + t.reverse(); + } else { + + // Exponents equal. Check digit by digit. + j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b; + + for ( a = b = 0; b < j; b++ ) { + + if ( xc[b] != yc[b] ) { + xLTy = xc[b] < yc[b]; + break; + } + } + } + + // x < y? Point xc to the array of the bigger number. + if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s; + + b = ( j = yc.length ) - ( i = xc.length ); + + // Append zeros to xc if shorter. + // No need to add zeros to yc if shorter as subtract only needs to start at yc.length. + if ( b > 0 ) for ( ; b--; xc[i++] = 0 ); + b = BASE - 1; + + // Subtract yc from xc. + for ( ; j > a; ) { + + if ( xc[--j] < yc[j] ) { + for ( i = j; i && !xc[--i]; xc[i] = b ); + --xc[i]; + xc[j] += BASE; + } + + xc[j] -= yc[j]; + } + + // Remove leading zeros and adjust exponent accordingly. + for ( ; xc[0] == 0; xc.splice(0, 1), --ye ); + + // Zero? + if ( !xc[0] ) { + + // Following IEEE 754 (2008) 6.3, + // n - n = +0 but n - n = -0 when rounding towards -Infinity. + y.s = ROUNDING_MODE == 3 ? -1 : 1; + y.c = [ y.e = 0 ]; + return y; + } + + // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity + // for finite x and y. + return normalise( y, xc, ye ); + }; + + + /* + * n % 0 = N + * n % N = N + * n % I = n + * 0 % n = 0 + * -0 % n = -0 + * 0 % 0 = N + * 0 % N = N + * 0 % I = 0 + * N % n = N + * N % 0 = N + * N % N = N + * N % I = N + * I % n = N + * I % 0 = N + * I % N = N + * I % I = N + * + * Return a new BigNumber whose value is the value of this BigNumber modulo the value of + * BigNumber(y, b). The result depends on the value of MODULO_MODE. + */ + P.modulo = P.mod = function ( y, b ) { + var q, s, + x = this; + + y = new BigNumber( y, b ); + + // Return NaN if x is Infinity or NaN, or y is NaN or zero. + if ( !x.c || !y.s || y.c && !y.c[0] ) { + return new BigNumber(NaN); + + // Return x if y is Infinity or x is zero. + } else if ( !y.c || x.c && !x.c[0] ) { + return new BigNumber(x); + } + + if ( MODULO_MODE == 9 ) { + + // Euclidian division: q = sign(y) * floor(x / abs(y)) + // r = x - qy where 0 <= r < abs(y) + s = y.s; + y.s = 1; + q = div( x, y, 0, 3 ); + y.s = s; + q.s *= s; + } else { + q = div( x, y, 0, MODULO_MODE ); + } + + return x.minus( q.times(y) ); + }; + + + /* + * n * 0 = 0 + * n * N = N + * n * I = I + * 0 * n = 0 + * 0 * 0 = 0 + * 0 * N = N + * 0 * I = N + * N * n = N + * N * 0 = N + * N * N = N + * N * I = N + * I * n = I + * I * 0 = N + * I * N = N + * I * I = I + * + * Return a new BigNumber whose value is the value of this BigNumber multiplied by the value + * of BigNumber(y, b). + */ + P.multipliedBy = P.times = function ( y, b ) { + var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc, + base, sqrtBase, + x = this, + xc = x.c, + yc = ( y = new BigNumber( y, b ) ).c; + + // Either NaN, ±Infinity or ±0? + if ( !xc || !yc || !xc[0] || !yc[0] ) { + + // Return NaN if either is NaN, or one is 0 and the other is Infinity. + if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) { + y.c = y.e = y.s = null; + } else { + y.s *= x.s; + + // Return ±Infinity if either is ±Infinity. + if ( !xc || !yc ) { + y.c = y.e = null; + + // Return ±0 if either is ±0. + } else { + y.c = [0]; + y.e = 0; + } + } + + return y; + } + + e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE ); + y.s *= x.s; + xcL = xc.length; + ycL = yc.length; + + // Ensure xc points to longer array and xcL to its length. + if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i; + + // Initialise the result array with zeros. + for ( i = xcL + ycL, zc = []; i--; zc.push(0) ); + + base = BASE; + sqrtBase = SQRT_BASE; + + for ( i = ycL; --i >= 0; ) { + c = 0; + ylo = yc[i] % sqrtBase; + yhi = yc[i] / sqrtBase | 0; + + for ( k = xcL, j = i + k; j > i; ) { + xlo = xc[--k] % sqrtBase; + xhi = xc[k] / sqrtBase | 0; + m = yhi * xlo + xhi * ylo; + xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c; + c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi; + zc[j--] = xlo % base; + } + + zc[j] = c; + } + + if (c) { + ++e; + } else { + zc.splice(0, 1); + } + + return normalise( y, zc, e ); + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber negated, + * i.e. multiplied by -1. + */ + P.negated = function () { + var x = new BigNumber(this); + x.s = -x.s || null; + return x; + }; + + + /* + * n + 0 = n + * n + N = N + * n + I = I + * 0 + n = n + * 0 + 0 = 0 + * 0 + N = N + * 0 + I = I + * N + n = N + * N + 0 = N + * N + N = N + * N + I = N + * I + n = I + * I + 0 = I + * I + N = N + * I + I = I + * + * Return a new BigNumber whose value is the value of this BigNumber plus the value of + * BigNumber(y, b). + */ + P.plus = function ( y, b ) { + var t, + x = this, + a = x.s; + + y = new BigNumber( y, b ); + b = y.s; + + // Either NaN? + if ( !a || !b ) return new BigNumber(NaN); + + // Signs differ? + if ( a != b ) { + y.s = -b; + return x.minus(y); + } + + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + + if ( !xe || !ye ) { + + // Return ±Infinity if either ±Infinity. + if ( !xc || !yc ) return new BigNumber( a / 0 ); + + // Either zero? + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. + if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 ); + } + + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + + // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts. + if ( a = xe - ye ) { + if ( a > 0 ) { + ye = xe; + t = yc; + } else { + a = -a; + t = xc; + } + + t.reverse(); + for ( ; a--; t.push(0) ); + t.reverse(); + } + + a = xc.length; + b = yc.length; + + // Point xc to the longer array, and b to the shorter length. + if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a; + + // Only start adding at yc.length - 1 as the further digits of xc can be ignored. + for ( a = 0; b; ) { + a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0; + xc[b] = BASE === xc[b] ? 0 : xc[b] % BASE; + } + + if (a) { + xc = [a].concat(xc); + ++ye; + } + + // No need to check for zero, as +x + +y != 0 && -x + -y != 0 + // ye = MAX_EXP + 1 possible + return normalise( y, xc, ye ); + }; + + + /* + * If sd is undefined or null or true or false, return the number of significant digits of + * the value of this BigNumber, or null if the value of this BigNumber is ±Infinity or NaN. + * If sd is true include integer-part trailing zeros in the count. + * + * Otherwise, if sd is a number, return a new BigNumber whose value is the value of this + * BigNumber rounded to a maximum of sd significant digits using rounding mode rm, or + * ROUNDING_MODE if rm is omitted. + * + * sd {number|boolean} number: significant digits: integer, 1 to MAX inclusive. + * boolean: whether to count integer-part trailing zeros: true or false. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {sd|rm}' + */ + P.precision = P.sd = function ( sd, rm ) { + var c, n, v, + x = this; + + if ( sd != null && sd !== !!sd ) { + intCheck( sd, 1, MAX ); + if ( rm == null ) rm = ROUNDING_MODE; + else intCheck( rm, 0, 8 ); + + return round( new BigNumber(x), sd, rm ); + } + + if ( !( c = x.c ) ) return null; + v = c.length - 1; + n = v * LOG_BASE + 1; + + if ( v = c[v] ) { + + // Subtract the number of trailing zeros of the last element. + for ( ; v % 10 == 0; v /= 10, n-- ); + + // Add the number of digits of the first element. + for ( v = c[0]; v >= 10; v /= 10, n++ ); + } + + if ( sd && x.e + 1 > n ) n = x.e + 1; + + return n; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber shifted by k places + * (powers of 10). Shift to the right if n > 0, and to the left if n < 0. + * + * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {k}' + */ + P.shiftedBy = function (k) { + intCheck( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER ); + return this.times( '1e' + k ); + }; + + + /* + * sqrt(-n) = N + * sqrt( N) = N + * sqrt(-I) = N + * sqrt( I) = I + * sqrt( 0) = 0 + * sqrt(-0) = -0 + * + * Return a new BigNumber whose value is the square root of the value of this BigNumber, + * rounded according to DECIMAL_PLACES and ROUNDING_MODE. + */ + P.squareRoot = P.sqrt = function () { + var m, n, r, rep, t, + x = this, + c = x.c, + s = x.s, + e = x.e, + dp = DECIMAL_PLACES + 4, + half = new BigNumber('0.5'); + + // Negative/NaN/Infinity/zero? + if ( s !== 1 || !c || !c[0] ) { + return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 ); + } + + // Initial estimate. + s = Math.sqrt( +x ); + + // Math.sqrt underflow/overflow? + // Pass x to Math.sqrt as integer, then adjust the exponent of the result. + if ( s == 0 || s == 1 / 0 ) { + n = coeffToString(c); + if ( ( n.length + e ) % 2 == 0 ) n += '0'; + s = Math.sqrt(n); + e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 ); + + if ( s == 1 / 0 ) { + n = '1e' + e; + } else { + n = s.toExponential(); + n = n.slice( 0, n.indexOf('e') + 1 ) + e; + } + + r = new BigNumber(n); + } else { + r = new BigNumber( s + '' ); + } + + // Check for zero. + // r could be zero if MIN_EXP is changed after the this value was created. + // This would cause a division by zero (x/t) and hence Infinity below, which would cause + // coeffToString to throw. + if ( r.c[0] ) { + e = r.e; + s = e + dp; + if ( s < 3 ) s = 0; + + // Newton-Raphson iteration. + for ( ; ; ) { + t = r; + r = half.times( t.plus( div( x, t, dp, 1 ) ) ); + + if ( coeffToString( t.c ).slice( 0, s ) === ( n = + coeffToString( r.c ) ).slice( 0, s ) ) { + + // The exponent of r may here be one less than the final result exponent, + // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits + // are indexed correctly. + if ( r.e < e ) --s; + n = n.slice( s - 3, s + 1 ); + + // The 4th rounding digit may be in error by -1 so if the 4 rounding digits + // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the + // iteration. + if ( n == '9999' || !rep && n == '4999' ) { + + // On the first iteration only, check to see if rounding up gives the + // exact result as the nines may infinitely repeat. + if ( !rep ) { + round( t, t.e + DECIMAL_PLACES + 2, 0 ); + + if ( t.times(t).eq(x) ) { + r = t; + break; + } + } + + dp += 4; + s += 4; + rep = 1; + } else { + + // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact + // result. If not, then there are further digits and m will be truthy. + if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) { + + // Truncate to the first rounding digit. + round( r, r.e + DECIMAL_PLACES + 2, 1 ); + m = !r.times(r).eq(x); + } + + break; + } + } + } + } + + return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m ); + }; + + + /* + * Return a string representing the value of this BigNumber in exponential notation and + * rounded using ROUNDING_MODE to dp fixed decimal places. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' + */ + P.toExponential = function ( dp, rm ) { + if ( dp != null ) { + intCheck( dp, 0, MAX ); + dp++; + } + return format( this, dp, rm, 1 ); + }; + + + /* + * Return a string representing the value of this BigNumber in fixed-point notation rounding + * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted. + * + * Note: as with JavaScript's number type, (-0).toFixed(0) is '0', + * but e.g. (-0.00001).toFixed(0) is '-0'. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' + */ + P.toFixed = function ( dp, rm ) { + if ( dp != null ) { + intCheck( dp, 0, MAX ); + dp = dp + this.e + 1; + } + return format( this, dp, rm ); + }; + + + /* + * Return a string representing the value of this BigNumber in fixed-point notation rounded + * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties + * of the FORMAT object (see BigNumber.set). + * + * FORMAT = { + * decimalSeparator : '.', + * groupSeparator : ',', + * groupSize : 3, + * secondaryGroupSize : 0, + * fractionGroupSeparator : '\xA0', // non-breaking space + * fractionGroupSize : 0 + * }; + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' + */ + P.toFormat = function ( dp, rm ) { + var str = this.toFixed( dp, rm ); + + if ( this.c ) { + var i, + arr = str.split('.'), + g1 = +FORMAT.groupSize, + g2 = +FORMAT.secondaryGroupSize, + groupSeparator = FORMAT.groupSeparator, + intPart = arr[0], + fractionPart = arr[1], + isNeg = this.s < 0, + intDigits = isNeg ? intPart.slice(1) : intPart, + len = intDigits.length; + + if (g2) i = g1, g1 = g2, g2 = i, len -= i; + + if ( g1 > 0 && len > 0 ) { + i = len % g1 || g1; + intPart = intDigits.substr( 0, i ); + + for ( ; i < len; i += g1 ) { + intPart += groupSeparator + intDigits.substr( i, g1 ); + } + + if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i); + if (isNeg) intPart = '-' + intPart; + } + + str = fractionPart + ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize ) + ? fractionPart.replace( new RegExp( '\\d{' + g2 + '}\\B', 'g' ), + '$&' + FORMAT.fractionGroupSeparator ) + : fractionPart ) + : intPart; + } + + return str; + }; + + + /* + * Return a string array representing the value of this BigNumber as a simple fraction with + * an integer numerator and an integer denominator. The denominator will be a positive + * non-zero value less than or equal to the specified maximum denominator. If a maximum + * denominator is not specified, the denominator will be the lowest value necessary to + * represent the number exactly. + * + * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator. + * + * '[BigNumber Error] Argument {not an integer|out of range} : {md}' + */ + P.toFraction = function (md) { + var arr, d, d0, d1, d2, e, exp, n, n0, n1, q, s, + x = this, + xc = x.c; + + if ( md != null ) { + n = new BigNumber(md); + + if ( !n.isInteger() || n.lt(ONE) ) { + throw Error + ( bignumberError + 'Argument ' + + ( n.isInteger() ? 'out of range: ' : 'not an integer: ' ) + md ); + } + } + + if ( !xc ) return x.toString(); + + d = new BigNumber(ONE); + n1 = d0 = new BigNumber(ONE); + d1 = n0 = new BigNumber(ONE); + s = coeffToString(xc); + + // Determine initial denominator. + // d is a power of 10 and the minimum max denominator that specifies the value exactly. + e = d.e = s.length - x.e - 1; + d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ]; + md = !md || n.comparedTo(d) > 0 ? ( e > 0 ? d : n1 ) : n; + + exp = MAX_EXP; + MAX_EXP = 1 / 0; + n = new BigNumber(s); + + // n0 = d1 = 0 + n0.c[0] = 0; + + for ( ; ; ) { + q = div( n, d, 0, 1 ); + d2 = d0.plus( q.times(d1) ); + if ( d2.comparedTo(md) == 1 ) break; + d0 = d1; + d1 = d2; + n1 = n0.plus( q.times( d2 = n1 ) ); + n0 = d2; + d = n.minus( q.times( d2 = d ) ); + n = d2; + } + + d2 = div( md.minus(d0), d1, 0, 1 ); + n0 = n0.plus( d2.times(n1) ); + d0 = d0.plus( d2.times(d1) ); + n0.s = n1.s = x.s; + e *= 2; + + // Determine which fraction is closer to x, n0/d0 or n1/d1 + arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().comparedTo( + div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1 + ? [ n1.toString(), d1.toString() ] + : [ n0.toString(), d0.toString() ]; + + MAX_EXP = exp; + return arr; + }; + + + /* + * Return the value of this BigNumber converted to a number primitive. + */ + P.toNumber = function () { + return +this; + }; + + + /* + * Return a BigNumber whose value is the value of this BigNumber exponentiated by n. + * + * If m is present, return the result modulo m. + * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE. + * If POW_PRECISION is non-zero and m is not present, round to POW_PRECISION using ROUNDING_MODE. + * + * The modular power operation works efficiently when x, n, and m are positive integers, + * otherwise it is equivalent to calculating x.exponentiatedBy(n).modulo(m) with a POW_PRECISION of 0. + * + * n {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. + * [m] {number|string|BigNumber} The modulus. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {n}' + * + * Performs 54 loop iterations for n of 9007199254740991. + */ + P.exponentiatedBy = P.pow = function ( n, m ) { + var i, k, y, z, + x = this; + + intCheck( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER ); + if ( m != null ) m = new BigNumber(m); + + if (m) { + if ( n > 1 && x.gt(ONE) && x.isInteger() && m.gt(ONE) && m.isInteger() ) { + x = x.mod(m); + } else { + z = m; + + // Nullify m so only a single mod operation is performed at the end. + m = null; + } + } else if (POW_PRECISION) { + + // Truncating each coefficient array to a length of k after each multiplication + // equates to truncating significant digits to POW_PRECISION + [28, 41], + // i.e. there will be a minimum of 28 guard digits retained. + //k = mathceil( POW_PRECISION / LOG_BASE + 1.5 ); // gives [9, 21] guard digits. + k = mathceil( POW_PRECISION / LOG_BASE + 2 ); + } + + y = new BigNumber(ONE); + + for ( i = mathfloor( n < 0 ? -n : n ); ; ) { + if ( i % 2 ) { + y = y.times(x); + if ( !y.c ) break; + if (k) { + if ( y.c.length > k ) y.c.length = k; + } else if (m) { + y = y.mod(m); + } + } + + i = mathfloor( i / 2 ); + if ( !i ) break; + x = x.times(x); + if (k) { + if ( x.c && x.c.length > k ) x.c.length = k; + } else if (m) { + x = x.mod(m); + } + } + + if (m) return y; + if ( n < 0 ) y = ONE.div(y); + + return z ? y.mod(z) : k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y; + }; + + + /* + * Return a string representing the value of this BigNumber rounded to sd significant digits + * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits + * necessary to represent the integer part of the value in fixed-point notation, then use + * exponential notation. + * + * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {sd|rm}' + */ + P.toPrecision = function ( sd, rm ) { + if ( sd != null ) intCheck( sd, 1, MAX ); + return format( this, sd, rm, 2 ); + }; + + + /* + * Return a string representing the value of this BigNumber in base b, or base 10 if b is + * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and + * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent + * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than + * TO_EXP_NEG, return exponential notation. + * + * [b] {number} Integer, 2 to ALPHABET.length inclusive. + * + * '[BigNumber Error] Base {not a primitive number|not an integer|out of range}: {b}' + */ + P.toString = function (b) { + var str, + n = this, + s = n.s, + e = n.e; + + // Infinity or NaN? + if ( e === null ) { + + if (s) { + str = 'Infinity'; + if ( s < 0 ) str = '-' + str; + } else { + str = 'NaN'; + } + } else { + str = coeffToString( n.c ); + + if ( b == null ) { + str = e <= TO_EXP_NEG || e >= TO_EXP_POS + ? toExponential( str, e ) + : toFixedPoint( str, e, '0' ); + } else { + intCheck( b, 2, ALPHABET.length, 'Base' ); + str = convertBase( toFixedPoint( str, e, '0' ), 10, b, s, true ); + } + + if ( s < 0 && n.c[0] ) str = '-' + str; + } + + return str; + }; + + + /* + * Return as toString, but do not accept a base argument, and include the minus sign for + * negative zero. + */ + P.valueOf = P.toJSON = function () { + var str, + n = this, + e = n.e; + + if ( e === null ) return n.toString(); + + str = coeffToString( n.c ); + + str = e <= TO_EXP_NEG || e >= TO_EXP_POS + ? toExponential( str, e ) + : toFixedPoint( str, e, '0' ); + + return n.s < 0 ? '-' + str : str; + }; + + + P._isBigNumber = true; + + if ( configObject != null ) BigNumber.set(configObject); + + return BigNumber; +} + + +// PRIVATE HELPER FUNCTIONS + + +function bitFloor(n) { + var i = n | 0; + return n > 0 || n === i ? i : i - 1; +} + + +// Return a coefficient array as a string of base 10 digits. +function coeffToString(a) { + var s, z, + i = 1, + j = a.length, + r = a[0] + ''; + + for ( ; i < j; ) { + s = a[i++] + ''; + z = LOG_BASE - s.length; + for ( ; z--; s = '0' + s ); + r += s; + } + + // Determine trailing zeros. + for ( j = r.length; r.charCodeAt(--j) === 48; ); + return r.slice( 0, j + 1 || 1 ); +} + + +// Compare the value of BigNumbers x and y. +function compare( x, y ) { + var a, b, + xc = x.c, + yc = y.c, + i = x.s, + j = y.s, + k = x.e, + l = y.e; + + // Either NaN? + if ( !i || !j ) return null; + + a = xc && !xc[0]; + b = yc && !yc[0]; + + // Either zero? + if ( a || b ) return a ? b ? 0 : -j : i; + + // Signs differ? + if ( i != j ) return i; + + a = i < 0; + b = k == l; + + // Either Infinity? + if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1; + + // Compare exponents. + if ( !b ) return k > l ^ a ? 1 : -1; + + j = ( k = xc.length ) < ( l = yc.length ) ? k : l; + + // Compare digit by digit. + for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1; + + // Compare lengths. + return k == l ? 0 : k > l ^ a ? 1 : -1; +} + + +/* + * Check that n is a primitive number, an integer, and in range, otherwise throw. + */ +function intCheck( n, min, max, name ) { + if ( n < min || n > max || n !== ( n < 0 ? mathceil(n) : mathfloor(n) ) ) { + throw Error + ( bignumberError + ( name || 'Argument' ) + ( typeof n == 'number' + ? n < min || n > max ? ' out of range: ' : ' not an integer: ' + : ' not a primitive number: ' ) + n ); + } +} + + +function isArray(obj) { + return Object.prototype.toString.call(obj) == '[object Array]'; +} + + +function toExponential( str, e ) { + return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) + + ( e < 0 ? 'e' : 'e+' ) + e; +} + + +function toFixedPoint( str, e, z ) { + var len, zs; + + // Negative exponent? + if ( e < 0 ) { + + // Prepend zeros. + for ( zs = z + '.'; ++e; zs += z ); + str = zs + str; + + // Positive exponent + } else { + len = str.length; + + // Append zeros. + if ( ++e > len ) { + for ( zs = z, e -= len; --e; zs += z ); + str += zs; + } else if ( e < len ) { + str = str.slice( 0, e ) + '.' + str.slice(e); + } + } + + return str; +} + + +// EXPORT + + +BigNumber = clone(); +BigNumber['default'] = BigNumber.BigNumber = BigNumber; + +export default BigNumber; \ No newline at end of file diff --git a/packages/instant/test/util/maybe_big_number.test.ts b/packages/instant/test/util/maybe_big_number.test.ts new file mode 100644 index 0000000000..f32e33eb14 --- /dev/null +++ b/packages/instant/test/util/maybe_big_number.test.ts @@ -0,0 +1,71 @@ +import { BigNumber } from '@0x/utils'; + +import { maybeBigNumberUtil } from '../../src/util/maybe_big_number'; + +// import PrevBigNumber from './dependencies/prevbignumber'; + +const BIG_NUMBER_1 = new BigNumber('10.1'); +const BIG_NUMBER_2 = new BigNumber('10.1'); +const BIG_NUMBER_3 = new BigNumber('11.1'); +// const PREVBIG_NUMBER_1 = new PrevBigNumber('11.1'); + +describe('maybeBigNumberUtil', () => { + describe('stringToMaybeBigNumber', () => { + it('should return undefined if stringValue is NaN', () => { + expect(maybeBigNumberUtil.stringToMaybeBigNumber('NaN')).toEqual(undefined); + }); + it('should return bignumber constructed with stringValue', () => { + const bn = maybeBigNumberUtil.stringToMaybeBigNumber('10.1'); + if (!!bn) { + expect(bn.toString()).toEqual('10.1'); + } + }); + it('should return undefined if stringValue is not valid (i.e not numeric)', () => { + expect(maybeBigNumberUtil.stringToMaybeBigNumber('test')).toEqual(undefined); + }); + }); + + describe('areMaybeBigNumbersEqual', () => { + it('should return true if val1 and val2 are equivalent BigNumber values', () => { + expect(maybeBigNumberUtil.areMaybeBigNumbersEqual(BIG_NUMBER_1, BIG_NUMBER_2)).toEqual(true); + }); + it('should return true if val1 and val2 are both undefined', () => { + expect(maybeBigNumberUtil.areMaybeBigNumbersEqual(undefined, undefined)).toEqual(true); + }); + it('should return false if either one val1 or val2 is undefined', () => { + expect(maybeBigNumberUtil.areMaybeBigNumbersEqual(BIG_NUMBER_1, undefined)).toEqual(false); + }); + it('should return false if val1 and val2 are equivalent values BigNumber', () => { + expect(maybeBigNumberUtil.areMaybeBigNumbersEqual(BIG_NUMBER_1, BIG_NUMBER_3)).toEqual(false); + }); + }); + + // describe('bigNumberOrStringToMaybeBigNumber', () => { + // it('should return BigNumber (>=v8.0.0) constructed with value if type is string', () => { + // const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('10.1'); + // if (!!bn) { + // expect(bn.toString()).toEqual('10.1'); + // } + // }); + // it('should return undefined if value is NaN', () => { + // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('NaN')).toEqual(undefined); + // }); + // it('should return undefined if value as string is not valid (i.e not numeric)', () => { + // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('test')).toEqual(undefined); + // }); + // it('should return undefined if value as string is not valid (i.e not numeric)', () => { + // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('test')).toEqual(undefined); + // }); + // it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber ( { + // const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(PREVBIG_NUMBER_1); + // expect(BigNumber.isBigNumber(bn)).toEqual(true); + // }); + // it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber (>=v8.0.0)', () => { + // const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(BIG_NUMBER_1); + // expect(BigNumber.isBigNumber(bn)).toEqual(true); + // }); + // it('should return undefined if value is not BigNumber or string', () => { + // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(true)).toEqual(undefined); + // }); + // }); +}); From 5aba9d698b25ddc5ce02ddbcd0dcb0c196472b0a Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 7 Feb 2019 14:54:12 +0000 Subject: [PATCH 04/39] Only include analytics on production builds --- packages/dev-tools-pages/assets/index.html | 84 +++++++++++----------- packages/dev-tools-pages/webpack.config.js | 5 +- yarn.lock | 32 +-------- 3 files changed, 50 insertions(+), 71 deletions(-) diff --git a/packages/dev-tools-pages/assets/index.html b/packages/dev-tools-pages/assets/index.html index 73797b9588..da7778343c 100644 --- a/packages/dev-tools-pages/assets/index.html +++ b/packages/dev-tools-pages/assets/index.html @@ -11,40 +11,42 @@
diff --git a/packages/dev-tools-pages/webpack.config.js b/packages/dev-tools-pages/webpack.config.js index ef2f98cf20..ae70fd83ee 100644 --- a/packages/dev-tools-pages/webpack.config.js +++ b/packages/dev-tools-pages/webpack.config.js @@ -82,7 +82,10 @@ const config = { module.exports = (_env, argv) => { let plugins = [ new CleanWebpackPlugin('public'), - ...pages.map(p => new HtmlWebpackPlugin(p)), + ...pages.map(p => { + p.environment = argv.mode; + return new HtmlWebpackPlugin(p); + }), new CopyWebpackPlugin([ { from: 'assets/crawl.html', to: 'index.html' }, { from: 'assets/fonts', to: 'fonts' }, diff --git a/yarn.lock b/yarn.lock index fae178e3e4..ab5d224923 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13461,16 +13461,6 @@ react-dom@^16.3.2: object-assign "^4.1.1" prop-types "^15.6.0" -react-dom@^16.4.2: - version "16.8.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.1.tgz#ec860f98853d09d39bafd3a6f1e12389d283dbb4" - integrity sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.13.1" - react-dom@^16.5.2: version "16.5.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.5.2.tgz#b69ee47aa20bab5327b2b9d7c1fe2a30f2cfa9d7" @@ -13528,8 +13518,8 @@ react-highlight@0xproject/react-highlight#react-peer-deps: dependencies: highlight.js "^9.11.0" highlightjs-solidity "^1.0.5" - react "^16.5.2" - react-dom "^16.5.2" + react "^16.4.2" + react-dom "^16.4.2" react-hot-loader@^4.3.3: version "4.3.4" @@ -13774,16 +13764,6 @@ react@^16.3.2: object-assign "^4.1.1" prop-types "^15.6.0" -react@^16.4.2: - version "16.8.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.8.1.tgz#ae11831f6cb2a05d58603a976afc8a558e852c4a" - integrity sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.13.1" - react@^16.5.2: version "16.5.2" resolved "https://registry.yarnpkg.com/react/-/react-16.5.2.tgz#19f6b444ed139baa45609eee6dc3d318b3895d42" @@ -14655,14 +14635,6 @@ schedule@^0.5.0: dependencies: object-assign "^4.1.1" -scheduler@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.1.tgz#1a217df1bfaabaf4f1b92a9127d5d732d85a9591" - integrity sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - schema-utils@^0.4.4: version "0.4.7" resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" From 6dabed5938a4ccefbc7c8966f8b3f4fbb83acf11 Mon Sep 17 00:00:00 2001 From: David Sun Date: Thu, 7 Feb 2019 16:45:56 -0500 Subject: [PATCH 05/39] updated order coercion utils architecture and testing --- packages/instant/src/index.umd.ts | 6 +- packages/instant/src/util/maybe_big_number.ts | 14 +- packages/instant/src/util/order_coercion.ts | 42 + .../instant/src/util/signed_order_coercion.ts | 26 - .../test/util/dependencies/prevbignumber.d.ts | 1772 ----------- .../test/util/dependencies/prevbignumber.js | 2705 ----------------- .../test/util/maybe_big_number.test.ts | 56 +- .../instant/test/util/order_coercion.test.ts | 103 + 8 files changed, 180 insertions(+), 4544 deletions(-) create mode 100644 packages/instant/src/util/order_coercion.ts delete mode 100644 packages/instant/src/util/signed_order_coercion.ts delete mode 100644 packages/instant/test/util/dependencies/prevbignumber.d.ts delete mode 100644 packages/instant/test/util/dependencies/prevbignumber.js create mode 100644 packages/instant/test/util/order_coercion.test.ts diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 45913aa47e..7b2b45a714 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -17,8 +17,8 @@ import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { Network, OrderSource } from './types'; import { analytics } from './util/analytics'; import { assert } from './util/assert'; +import { orderCoercionUtil } from './util/order_coercion'; import { providerFactory } from './util/provider_factory'; -import { signedOrderCoercionUtil } from './util/signed_order_coercion'; import { util } from './util/util'; const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); @@ -94,8 +94,8 @@ export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { } export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { - if (!_.isString(config.orderSource)) { - config.orderSource = config.orderSource.map(signedOrderCoercionUtil.bigNumberCoercion); + if (_.isArray(config.orderSource)) { + config.orderSource = orderCoercionUtil.coerceOrderArrayFieldsToBigNumber(config.orderSource); } validateInstantRenderConfig(config, selector); diff --git a/packages/instant/src/util/maybe_big_number.ts b/packages/instant/src/util/maybe_big_number.ts index 7e206a1253..95fbd86952 100644 --- a/packages/instant/src/util/maybe_big_number.ts +++ b/packages/instant/src/util/maybe_big_number.ts @@ -16,8 +16,14 @@ export const maybeBigNumberUtil = { return validBigNumber.isNaN() ? undefined : validBigNumber; }, + areMaybeBigNumbersEqual: (val1: Maybe, val2: Maybe): boolean => { + if (!_.isUndefined(val1) && !_.isUndefined(val2)) { + return val1.isEqualTo(val2); + } + return _.isUndefined(val1) && _.isUndefined(val2); + }, // converts a BigNumber or String to the BigNumber used by 0x libraries - bigNumberOrStringToMaybeBigNumber: (value: any): Maybe => { + toMaybeBigNumber: (value: any): Maybe => { if (_.isString(value)) { return maybeBigNumberUtil.stringToMaybeBigNumber(value); } @@ -27,10 +33,4 @@ export const maybeBigNumberUtil = { } return undefined; }, - areMaybeBigNumbersEqual: (val1: Maybe, val2: Maybe): boolean => { - if (!_.isUndefined(val1) && !_.isUndefined(val2)) { - return val1.isEqualTo(val2); - } - return _.isUndefined(val1) && _.isUndefined(val2); - }, }; diff --git a/packages/instant/src/util/order_coercion.ts b/packages/instant/src/util/order_coercion.ts new file mode 100644 index 0000000000..a1b468bafc --- /dev/null +++ b/packages/instant/src/util/order_coercion.ts @@ -0,0 +1,42 @@ +import { BigNumber } from '@0x/utils'; +import * as _ from 'lodash'; + +import { maybeBigNumberUtil } from './maybe_big_number'; + +const coerceBigNumberOrString = (value: any): BigNumber => { + const bn = maybeBigNumberUtil.toMaybeBigNumber(value); + return !!bn ? bn : value; +}; + +// function implies that the signed order already has been validated +export const orderCoercionUtil = { + // coerces order big number values to the BigNumber version utilized by 0x + coerceFieldsToBigNumbers(obj: any, fields: string[]): any { + const result = _.assign({}, obj); + _.each(fields, field => { + _.update(result, field, (value: string) => { + if (_.isUndefined(value)) { + throw new Error(`Could not find field '${field}' while converting fields to BigNumber.`); + } + return coerceBigNumberOrString(value); + }); + }); + return result; + }, + + coerceOrderFieldsToBigNumber: (order: any): any => { + return orderCoercionUtil.coerceFieldsToBigNumbers(order, [ + 'makerFee', + 'takerFee', + 'makerAssetAmount', + 'takerAssetAmount', + 'salt', + 'expirationTimeSeconds', + ]); + }, + coerceOrderArrayFieldsToBigNumber: (orders: any[]): any[] => { + return _.map(orders, (value: any) => { + return orderCoercionUtil.coerceOrderFieldsToBigNumber(value); + }); + }, +}; diff --git a/packages/instant/src/util/signed_order_coercion.ts b/packages/instant/src/util/signed_order_coercion.ts deleted file mode 100644 index 4209e05e11..0000000000 --- a/packages/instant/src/util/signed_order_coercion.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { maybeBigNumberUtil } from './maybe_big_number'; - -const coerceBigNumberOrString = (value: any): BigNumber => { - const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(value); - return !!bn ? bn : value; -}; - -// function implies that the signed order already has been validated -export const signedOrderCoercionUtil = { - // coerces order big number values to the BigNumber version utilized by 0x - bigNumberCoercion: (order: SignedOrder): SignedOrder => { - return { - ...order, - makerFee: coerceBigNumberOrString(order.makerFee), - takerFee: coerceBigNumberOrString(order.takerFee), - makerAssetAmount: coerceBigNumberOrString(order.makerAssetAmount), - takerAssetAmount: coerceBigNumberOrString(order.takerAssetAmount), - salt: coerceBigNumberOrString(order.salt), - expirationTimeSeconds: coerceBigNumberOrString(order.expirationTimeSeconds), - }; - }, -}; diff --git a/packages/instant/test/util/dependencies/prevbignumber.d.ts b/packages/instant/test/util/dependencies/prevbignumber.d.ts deleted file mode 100644 index 9b802ec3e1..0000000000 --- a/packages/instant/test/util/dependencies/prevbignumber.d.ts +++ /dev/null @@ -1,1772 +0,0 @@ -// Type definitions for bignumber.js >=6.0.0 -// Project: https://github.com/MikeMcl/bignumber.js -// Definitions by: Michael Mclaughlin -// Definitions: https://github.com/MikeMcl/bignumber.js - -// Documentation: http://mikemcl.github.io/bignumber.js/ -// -// Exports (available globally or when using import): -// -// class BigNumber (default export) -// type BigNumber.Constructor -// type BigNumber.Instance -// type BigNumber.ModuloMode -// type BigNumber.RoundingMOde -// type BigNumber.Value -// interface BigNumber.Config -// interface BigNumber.Format -// -// Example (alternative syntax commented-out): -// -// import {BigNumber} from "bignumber.js" -// //import BigNumber from "bignumber.js" -// -// let rm: BigNumber.RoundingMode = BigNumber.ROUND_UP; -// let f: BigNumber.Format = { decimalSeparator: ',' }; -// let c: BigNumber.Config = { DECIMAL_PLACES: 4, ROUNDING_MODE: rm, FORMAT: f }; -// BigNumber.config(c); -// -// let v: BigNumber.Value = '12345.6789'; -// let b: BigNumber = new BigNumber(v); -// //let b: BigNumber.Instance = new BigNumber(v); -// -// The use of compiler option `--strictNullChecks` is recommended. - - -type BigNumberConstructor = typeof BigNumber; -type BigNumberInstance = BigNumber; -type BigNumberModuloMode = BigNumberRoundingMode | 9; -type BigNumberRoundingMode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; -type BigNumberValue = string | number | BigNumber; - -/** - * See `BigNumber.config` and `BigNumber.clone`. - */ -interface BigNumberConfig { - - /** - * An integer, 0 to 1e+9. Default value: 20. - * - * The maximum number of decimal places of the result of operations involving division, i.e. - * division, square root and base conversion operations, and exponentiation when the exponent is - * negative. - * - * ```ts - * BigNumber.config({ DECIMAL_PLACES: 5 }) - * BigNumber.set({ DECIMAL_PLACES: 5 }) - * ``` - */ - DECIMAL_PLACES?: number; - - /** - * An integer, 0 to 8. Default value: `BigNumber.ROUND_HALF_UP` (4). - * - * The rounding mode used in operations that involve division (see `DECIMAL_PLACES`) and the - * default rounding mode of the `decimalPlaces`, `precision`, `toExponential`, `toFixed`, - * `toFormat` and `toPrecision` methods. - * - * The modes are available as enumerated properties of the BigNumber constructor. - * - * ```ts - * BigNumber.config({ ROUNDING_MODE: 0 }) - * BigNumber.set({ ROUNDING_MODE: BigNumber.ROUND_UP }) - * ``` - */ - ROUNDING_MODE?: BigNumberRoundingMode; - - /** - * An integer, 0 to 1e+9, or an array, [-1e+9 to 0, 0 to 1e+9]. - * Default value: `[-7, 20]`. - * - * The exponent value(s) at which `toString` returns exponential notation. - * - * If a single number is assigned, the value is the exponent magnitude. - * - * If an array of two numbers is assigned then the first number is the negative exponent value at - * and beneath which exponential notation is used, and the second number is the positive exponent - * value at and above which exponential notation is used. - * - * For example, to emulate JavaScript numbers in terms of the exponent values at which they begin - * to use exponential notation, use `[-7, 20]`. - * - * ```ts - * BigNumber.config({ EXPONENTIAL_AT: 2 }) - * new BigNumber(12.3) // '12.3' e is only 1 - * new BigNumber(123) // '1.23e+2' - * new BigNumber(0.123) // '0.123' e is only -1 - * new BigNumber(0.0123) // '1.23e-2' - * - * BigNumber.config({ EXPONENTIAL_AT: [-7, 20] }) - * new BigNumber(123456789) // '123456789' e is only 8 - * new BigNumber(0.000000123) // '1.23e-7' - * - * // Almost never return exponential notation: - * BigNumber.config({ EXPONENTIAL_AT: 1e+9 }) - * - * // Always return exponential notation: - * BigNumber.config({ EXPONENTIAL_AT: 0 }) - * ``` - * - * Regardless of the value of `EXPONENTIAL_AT`, the `toFixed` method will always return a value in - * normal notation and the `toExponential` method will always return a value in exponential form. - * Calling `toString` with a base argument, e.g. `toString(10)`, will also always return normal - * notation. - */ - EXPONENTIAL_AT?: number|[number, number]; - - /** - * An integer, magnitude 1 to 1e+9, or an array, [-1e+9 to -1, 1 to 1e+9]. - * Default value: `[-1e+9, 1e+9]`. - * - * The exponent value(s) beyond which overflow to Infinity and underflow to zero occurs. - * - * If a single number is assigned, it is the maximum exponent magnitude: values wth a positive - * exponent of greater magnitude become Infinity and those with a negative exponent of greater - * magnitude become zero. - * - * If an array of two numbers is assigned then the first number is the negative exponent limit and - * the second number is the positive exponent limit. - * - * For example, to emulate JavaScript numbers in terms of the exponent values at which they - * become zero and Infinity, use [-324, 308]. - * - * ```ts - * BigNumber.config({ RANGE: 500 }) - * BigNumber.config().RANGE // [ -500, 500 ] - * new BigNumber('9.999e499') // '9.999e+499' - * new BigNumber('1e500') // 'Infinity' - * new BigNumber('1e-499') // '1e-499' - * new BigNumber('1e-500') // '0' - * - * BigNumber.config({ RANGE: [-3, 4] }) - * new BigNumber(99999) // '99999' e is only 4 - * new BigNumber(100000) // 'Infinity' e is 5 - * new BigNumber(0.001) // '0.01' e is only -3 - * new BigNumber(0.0001) // '0' e is -4 - * ``` - * The largest possible magnitude of a finite BigNumber is 9.999...e+1000000000. - * The smallest possible magnitude of a non-zero BigNumber is 1e-1000000000. - */ - RANGE?: number|[number, number]; - - /** - * A boolean: `true` or `false`. Default value: `false`. - * - * The value that determines whether cryptographically-secure pseudo-random number generation is - * used. If `CRYPTO` is set to true then the random method will generate random digits using - * `crypto.getRandomValues` in browsers that support it, or `crypto.randomBytes` if using a - * version of Node.js that supports it. - * - * If neither function is supported by the host environment then attempting to set `CRYPTO` to - * `true` will fail and an exception will be thrown. - * - * If `CRYPTO` is `false` then the source of randomness used will be `Math.random` (which is - * assumed to generate at least 30 bits of randomness). - * - * See `BigNumber.random`. - * - * ```ts - * BigNumber.config({ CRYPTO: true }) - * BigNumber.config().CRYPTO // true - * BigNumber.random() // 0.54340758610486147524 - * ``` - */ - CRYPTO?: boolean; - - /** - * An integer, 0 to 9. Default value: `BigNumber.ROUND_DOWN` (1). - * - * The modulo mode used when calculating the modulus: `a mod n`. - * The quotient, `q = a / n`, is calculated according to the `ROUNDING_MODE` that corresponds to - * the chosen `MODULO_MODE`. - * The remainder, `r`, is calculated as: `r = a - n * q`. - * - * The modes that are most commonly used for the modulus/remainder operation are shown in the - * following table. Although the other rounding modes can be used, they may not give useful - * results. - * - * Property | Value | Description - * :------------------|:------|:------------------------------------------------------------------ - * `ROUND_UP` | 0 | The remainder is positive if the dividend is negative. - * `ROUND_DOWN` | 1 | The remainder has the same sign as the dividend. - * | | Uses 'truncating division' and matches JavaScript's `%` operator . - * `ROUND_FLOOR` | 3 | The remainder has the same sign as the divisor. - * | | This matches Python's `%` operator. - * `ROUND_HALF_EVEN` | 6 | The IEEE 754 remainder function. - * `EUCLID` | 9 | The remainder is always positive. - * | | Euclidian division: `q = sign(n) * floor(a / abs(n))` - * - * The rounding/modulo modes are available as enumerated properties of the BigNumber constructor. - * - * See `modulo`. - * - * ```ts - * BigNumber.config({ MODULO_MODE: BigNumber.EUCLID }) - * BigNumber.set({ MODULO_MODE: 9 }) // equivalent - * ``` - */ - MODULO_MODE?: BigNumberModuloMode; - - /** - * An integer, 0 to 1e+9. Default value: 0. - * - * The maximum precision, i.e. number of significant digits, of the result of the power operation - * - unless a modulus is specified. - * - * If set to 0, the number of significant digits will not be limited. - * - * See `exponentiatedBy`. - * - * ```ts - * BigNumber.config({ POW_PRECISION: 100 }) - * ``` - */ - POW_PRECISION?: number; - - /** - * An object including any number of the properties shown below. - * - * The object configures the format of the string returned by the `toFormat` method. - * The example below shows the properties of the object that are recognised, and - * their default values. - * - * Unlike the other configuration properties, the values of the properties of the `FORMAT` object - * will not be checked for validity - the existing object will simply be replaced by the object - * that is passed in. - * - * See `toFormat`. - * - * ```ts - * BigNumber.config({ - * FORMAT: { - * // the decimal separator - * decimalSeparator: '.', - * // the grouping separator of the integer part - * groupSeparator: ',', - * // the primary grouping size of the integer part - * groupSize: 3, - * // the secondary grouping size of the integer part - * secondaryGroupSize: 0, - * // the grouping separator of the fraction part - * fractionGroupSeparator: ' ', - * // the grouping size of the fraction part - * fractionGroupSize: 0 - * } - * }) - * ``` - */ - FORMAT?: BigNumberFormat; - - /** - * A string representing the alphabet used for base conversion. - * Default value: `'0123456789abcdefghijklmnopqrstuvwxyz'`. - * - * The length of the alphabet corresponds to the maximum value of the base argument that can be - * passed to the BigNumber constructor or `toString`. There is no maximum length, but it must be - * at least 2 characters long, and it must not contain a repeated character, or `'.'` - the - * decimal separator for all values whatever their base. - * - * ```ts - * // duodecimal (base 12) - * BigNumber.config({ ALPHABET: '0123456789TE' }) - * x = new BigNumber('T', 12) - * x.toString() // '10' - * x.toString(12) // 'T' - * ``` - */ - ALPHABET?: string; -} - - -/** - * See `FORMAT` and `toFormat`. - */ -interface BigNumberFormat { - - /** - * The decimal separator. - */ - decimalSeparator?: string; - - /** - * The grouping separator of the integer part. - */ - groupSeparator?: string; - - /** - * The primary grouping size of the integer part. - */ - groupSize?: number; - - /** - * The secondary grouping size of the integer part. - */ - secondaryGroupSize?: number; - - /** - * The grouping separator of the fraction part. - */ - fractionGroupSeparator?: string; - - /** - * The grouping size of the fraction part. - */ - fractionGroupSize?: number; -} - - -export declare class BigNumber { - - /** - * Used internally by the `BigNumber.isBigNumber` method. - */ - private readonly _isBigNumber: true; - - /** - * The coefficient of the value of this BigNumber, an array of base 1e14 integer numbers. - */ - readonly c: number[]; - - /** - * The exponent of the value of this BigNumber, an integer number, -1000000000 to 1000000000. - */ - readonly e: number; - - /** - * The sign of the value of this BigNumber, -1 or 1. - */ - readonly s: number; - - /** - * Returns a new instance of BigNumber with value `n`. - * - * Legitimate values for `n` include ±0, ±`Infinity` and `NaN`. - * - * Values of type number with more than 15 significant digits are considered invalid as calling - * `toString` or `valueOf` on such numbers may not result in the intended value. - * - * ```ts - * console.log( 823456789123456.3 ); // 823456789123456.2 - * ``` - * - * There is no limit to the number of digits of a value of type string (other than that of - * JavaScript's maximum array size). Decimal string values may be in exponential, as well as - * normal (fixed-point) notation. Non-decimal values must be in normal notation. - * - * String values in hexadecimal literal form, e.g. '0xff', are valid, as are string values with - * the octal and binary prefixs '0o' and '0b'. String values in octal literal form without the - * prefix will be interpreted as decimals, e.g. '011' is interpreted as 11, not 9. - * - * Values in any base may have fraction digits. - * - * If a base is specified, `n` is rounded according to the current `DECIMAL_PLACES` and - * `ROUNDING_MODE` settings. If base is omitted, or is `null` or `undefined`, base 10 is assumed. - * - * Throws an invalid `value` or `base`. - * - * ```ts - * x = new BigNumber(9) // '9' - * y = new BigNumber(x) // '9' - * - * // 'new' is optional - * BigNumber(435.345) // '435.345' - * - * new BigNumber('5032485723458348569331745.33434346346912144534543') - * new BigNumber('4.321e+4') // '43210' - * new BigNumber('-735.0918e-430') // '-7.350918e-428' - * new BigNumber(Infinity) // 'Infinity' - * new BigNumber(NaN) // 'NaN' - * new BigNumber('.5') // '0.5' - * new BigNumber('+2') // '2' - * new BigNumber(-10110100.1, 2) // '-180.5' - * new BigNumber(-0b10110100.1) // '-180.5' - * new BigNumber('123412421.234324', 5) // '607236.557696' - * new BigNumber('ff.8', 16) // '255.5' - * new BigNumber('0xff.8') // '255.5' - * - * // The following throws 'Not a base 2 number'. - * new BigNumber(9, 2) - * - * // The following throws 'Number primitive has more than 15 significant digits'. - * new BigNumber(96517860459076817.4395) - * - * // The following throws 'Not a number'. - * new BigNumber('blurgh') - * - * // A value is only rounded by the constructor if a base is specified. - * BigNumber.config({ DECIMAL_PLACES: 5 }) - * new BigNumber(1.23456789) // '1.23456789' - * new BigNumber(1.23456789, 10) // '1.23457' - * ``` - * - * @param n A numeric value. - * @param base The base of n, integer, 2 to 36 (or `ALPHABET.length`, see `ALPHABET`). - */ - constructor(n: BigNumberValue, base?: number); - - /** - * Returns a BigNumber whose value is the absolute value, i.e. the magnitude, of the value of this - * BigNumber. - * - * The return value is always exact and unrounded. - * - * ```ts - * x = new BigNumber(-0.8) - * x.absoluteValue() // '0.8' - * ``` - */ - absoluteValue(): BigNumber; - - /** - * Returns a BigNumber whose value is the absolute value, i.e. the magnitude, of the value of this - * BigNumber. - * - * The return value is always exact and unrounded. - * - * ```ts - * x = new BigNumber(-0.8) - * x.abs() // '0.8' - * ``` - */ - abs(): BigNumber; - - /** - * Returns | | - * :-------:|:--------------------------------------------------------------| - * 1 | If the value of this BigNumber is greater than the value of `n` - * -1 | If the value of this BigNumber is less than the value of `n` - * 0 | If this BigNumber and `n` have the same value - * `null` | If the value of either this BigNumber or `n` is `NaN` - * - * ```ts - * - * x = new BigNumber(Infinity) - * y = new BigNumber(5) - * x.comparedTo(y) // 1 - * x.comparedTo(x.minus(1)) // 0 - * y.comparedTo(NaN) // null - * y.comparedTo('110', 2) // -1 - * ``` - * @param n A numeric value. - * @param [base] The base of n. - */ - comparedTo(n: BigNumberValue, base?: number): number; - - /** - * Returns a BigNumber whose value is the value of this BigNumber rounded by rounding mode - * `roundingMode` to a maximum of `decimalPlaces` decimal places. - * - * If `decimalPlaces` is omitted, or is `null` or `undefined`, the return value is the number of - * decimal places of the value of this BigNumber, or `null` if the value of this BigNumber is - * ±`Infinity` or `NaN`. - * - * If `roundingMode` is omitted, or is `null` or `undefined`, `ROUNDING_MODE` is used. - * - * Throws if `decimalPlaces` or `roundingMode` is invalid. - * - * ```ts - * x = new BigNumber(1234.56) - * x.decimalPlaces() // 2 - * x.decimalPlaces(1) // '1234.6' - * x.decimalPlaces(2) // '1234.56' - * x.decimalPlaces(10) // '1234.56' - * x.decimalPlaces(0, 1) // '1234' - * x.decimalPlaces(0, 6) // '1235' - * x.decimalPlaces(1, 1) // '1234.5' - * x.decimalPlaces(1, BigNumber.ROUND_HALF_EVEN) // '1234.6' - * x // '1234.56' - * y = new BigNumber('9.9e-101') - * y.decimalPlaces() // 102 - * ``` - * - * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. - * @param [roundingMode] Rounding mode, integer, 0 to 8. - */ - decimalPlaces(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber rounded by rounding mode - * `roundingMode` to a maximum of `decimalPlaces` decimal places. - * - * If `decimalPlaces` is omitted, or is `null` or `undefined`, the return value is the number of - * decimal places of the value of this BigNumber, or `null` if the value of this BigNumber is - * ±`Infinity` or `NaN`. - * - * If `roundingMode` is omitted, or is `null` or `undefined`, `ROUNDING_MODE` is used. - * - * Throws if `decimalPlaces` or `roundingMode` is invalid. - * - * ```ts - * x = new BigNumber(1234.56) - * x.dp() // 2 - * x.dp(1) // '1234.6' - * x.dp(2) // '1234.56' - * x.dp(10) // '1234.56' - * x.dp(0, 1) // '1234' - * x.dp(0, 6) // '1235' - * x.dp(1, 1) // '1234.5' - * x.dp(1, BigNumber.ROUND_HALF_EVEN) // '1234.6' - * x // '1234.56' - * y = new BigNumber('9.9e-101') - * y.dp() // 102 - * ``` - * - * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. - * @param [roundingMode] Rounding mode, integer, 0 to 8. - */ - dp(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber divided by `n`, rounded - * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. - * - * ```ts - * x = new BigNumber(355) - * y = new BigNumber(113) - * x.dividedBy(y) // '3.14159292035398230088' - * x.dividedBy(5) // '71' - * x.dividedBy(47, 16) // '5' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - dividedBy(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber divided by `n`, rounded - * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. - * - * ```ts - * x = new BigNumber(355) - * y = new BigNumber(113) - * x.div(y) // '3.14159292035398230088' - * x.div(5) // '71' - * x.div(47, 16) // '5' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - div(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the integer part of dividing the value of this BigNumber by - * `n`. - * - * ```ts - * x = new BigNumber(5) - * y = new BigNumber(3) - * x.dividedToIntegerBy(y) // '1' - * x.dividedToIntegerBy(0.7) // '7' - * x.dividedToIntegerBy('0.f', 16) // '5' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - dividedToIntegerBy(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the integer part of dividing the value of this BigNumber by - * `n`. - * - * ```ts - * x = new BigNumber(5) - * y = new BigNumber(3) - * x.idiv(y) // '1' - * x.idiv(0.7) // '7' - * x.idiv('0.f', 16) // '5' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - idiv(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber exponentiated by `n`, i.e. - * raised to the power `n`, and optionally modulo a modulus `m`. - * - * If `n` is negative the result is rounded according to the current `DECIMAL_PLACES` and - * `ROUNDING_MODE` settings. - * - * As the number of digits of the result of the power operation can grow so large so quickly, - * e.g. 123.456**10000 has over 50000 digits, the number of significant digits calculated is - * limited to the value of the `POW_PRECISION` setting (unless a modulus `m` is specified). - * - * By default `POW_PRECISION` is set to 0. This means that an unlimited number of significant - * digits will be calculated, and that the method's performance will decrease dramatically for - * larger exponents. - * - * If `m` is specified and the value of `m`, `n` and this BigNumber are positive integers, then a - * fast modular exponentiation algorithm is used, otherwise if any of the values is not a positive - * integer the operation will simply be performed as `x.exponentiatedBy(n).modulo(m)` with a - * `POW_PRECISION` of 0. - * - * Throws if `n` is not a primitive number, or is not an integer, or is out of range. - * - * ```ts - * Math.pow(0.7, 2) // 0.48999999999999994 - * x = new BigNumber(0.7) - * x.exponentiatedBy(2) // '0.49' - * BigNumber(3).exponentiatedBy(-2) // '0.11111111111111111111' - * ``` - * - * @param n The exponent, an integer, -9007199254740991 to 9007199254740991. - * @param [m] The modulus, a positive integer. - */ - exponentiatedBy(n: number, m?: BigNumberValue): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber exponentiated by `n`, i.e. - * raised to the power `n`, and optionally modulo a modulus `m`. - * - * If `n` is negative the result is rounded according to the current `DECIMAL_PLACES` and - * `ROUNDING_MODE` settings. - * - * As the number of digits of the result of the power operation can grow so large so quickly, - * e.g. 123.456**10000 has over 50000 digits, the number of significant digits calculated is - * limited to the value of the `POW_PRECISION` setting (unless a modulus `m` is specified). - * - * By default `POW_PRECISION` is set to 0. This means that an unlimited number of significant - * digits will be calculated, and that the method's performance will decrease dramatically for - * larger exponents. - * - * If `m` is specified and the value of `m`, `n` and this BigNumber are positive integers, then a - * fast modular exponentiation algorithm is used, otherwise if any of the values is not a positive - * integer the operation will simply be performed as `x.exponentiatedBy(n).modulo(m)` with a - * `POW_PRECISION` of 0. - * - * Throws if `n` is not a primitive number or an integer, or is out of range. - * - * ```ts - * Math.pow(0.7, 2) // 0.48999999999999994 - * x = new BigNumber(0.7) - * x.pow(2) // '0.49' - * BigNumber(3).pow(-2) // '0.11111111111111111111' - * ``` - * - * @param n The exponent, an integer, -9007199254740991 to 9007199254740991. - * @param [m] The modulus, a positive integer. - */ - pow(n: number, m?: BigNumberValue): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber rounded to an integer using - * rounding mode `rm`. - * - * If `rm` is omitted, or is `null` or `undefined`, `ROUNDING_MODE` is used. - * - * Throws if `rm` is invalid. - * - * ```ts - * x = new BigNumber(123.456) - * x.integerValue() // '123' - * x.integerValue(BigNumber.ROUND_CEIL) // '124' - * y = new BigNumber(-12.7) - * y.integerValue() // '-13' - * x.integerValue(BigNumber.ROUND_DOWN) // '-12' - * ``` - * - * @param {BigNumberRoundingMode} [rm] The roundng mode, an integer, 0 to 8. - */ - integerValue(rm?: BigNumberRoundingMode): BigNumber; - - /** - * Returns `true` if the value of this BigNumber is equal to the value of `n`, otherwise returns - * `false`. - * - * As with JavaScript, `NaN` does not equal `NaN`. - * - * ```ts - * 0 === 1e-324 // true - * x = new BigNumber(0) - * x.isEqualTo('1e-324') // false - * BigNumber(-0).isEqualTo(x) // true ( -0 === 0 ) - * BigNumber(255).isEqualTo('ff', 16) // true - * - * y = new BigNumber(NaN) - * y.isEqualTo(NaN) // false - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - isEqualTo(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is equal to the value of `n`, otherwise returns - * `false`. - * - * As with JavaScript, `NaN` does not equal `NaN`. - * - * ```ts - * 0 === 1e-324 // true - * x = new BigNumber(0) - * x.eq('1e-324') // false - * BigNumber(-0).eq(x) // true ( -0 === 0 ) - * BigNumber(255).eq('ff', 16) // true - * - * y = new BigNumber(NaN) - * y.eq(NaN) // false - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - eq(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is a finite number, otherwise returns `false`. - * - * The only possible non-finite values of a BigNumber are `NaN`, `Infinity` and `-Infinity`. - * - * ```ts - * x = new BigNumber(1) - * x.isFinite() // true - * y = new BigNumber(Infinity) - * y.isFinite() // false - * ``` - */ - isFinite(): boolean; - - /** - * Returns `true` if the value of this BigNumber is greater than the value of `n`, otherwise - * returns `false`. - * - * ```ts - * 0.1 > (0.3 - 0.2) // true - * x = new BigNumber(0.1) - * x.isGreaterThan(BigNumber(0.3).minus(0.2)) // false - * BigNumber(0).isGreaterThan(x) // false - * BigNumber(11, 3).isGreaterThan(11.1, 2) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - isGreaterThan(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is greater than the value of `n`, otherwise - * returns `false`. - * - * ```ts - * 0.1 > (0.3 - 0 // true - * x = new BigNumber(0.1) - * x.gt(BigNumber(0.3).minus(0.2)) // false - * BigNumber(0).gt(x) // false - * BigNumber(11, 3).gt(11.1, 2) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - gt(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is greater than or equal to the value of `n`, - * otherwise returns `false`. - * - * ```ts - * (0.3 - 0.2) >= 0.1 // false - * x = new BigNumber(0.3).minus(0.2) - * x.isGreaterThanOrEqualTo(0.1) // true - * BigNumber(1).isGreaterThanOrEqualTo(x) // true - * BigNumber(10, 18).isGreaterThanOrEqualTo('i', 36) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - isGreaterThanOrEqualTo(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is greater than or equal to the value of `n`, - * otherwise returns `false`. - * - * ```ts - * (0.3 - 0.2) >= 0.1 // false - * x = new BigNumber(0.3).minus(0.2) - * x.gte(0.1) // true - * BigNumber(1).gte(x) // true - * BigNumber(10, 18).gte('i', 36) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - gte(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is an integer, otherwise returns `false`. - * - * ```ts - * x = new BigNumber(1) - * x.isInteger() // true - * y = new BigNumber(123.456) - * y.isInteger() // false - * ``` - */ - isInteger(): boolean; - - /** - * Returns `true` if the value of this BigNumber is less than the value of `n`, otherwise returns - * `false`. - * - * ```ts - * (0.3 - 0.2) < 0.1 // true - * x = new BigNumber(0.3).minus(0.2) - * x.isLessThan(0.1) // false - * BigNumber(0).isLessThan(x) // true - * BigNumber(11.1, 2).isLessThan(11, 3) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - isLessThan(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is less than the value of `n`, otherwise returns - * `false`. - * - * ```ts - * (0.3 - 0.2) < 0.1 // true - * x = new BigNumber(0.3).minus(0.2) - * x.lt(0.1) // false - * BigNumber(0).lt(x) // true - * BigNumber(11.1, 2).lt(11, 3) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - lt(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is less than or equal to the value of `n`, - * otherwise returns `false`. - * - * ```ts - * 0.1 <= (0.3 - 0.2) // false - * x = new BigNumber(0.1) - * x.isLessThanOrEqualTo(BigNumber(0.3).minus(0.2)) // true - * BigNumber(-1).isLessThanOrEqualTo(x) // true - * BigNumber(10, 18).isLessThanOrEqualTo('i', 36) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - isLessThanOrEqualTo(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is less than or equal to the value of `n`, - * otherwise returns `false`. - * - * ```ts - * 0.1 <= (0.3 - 0.2) // false - * x = new BigNumber(0.1) - * x.lte(BigNumber(0.3).minus(0.2)) // true - * BigNumber(-1).lte(x) // true - * BigNumber(10, 18).lte('i', 36) // true - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - lte(n: BigNumberValue, base?: number): boolean; - - /** - * Returns `true` if the value of this BigNumber is `NaN`, otherwise returns `false`. - * - * ```ts - * x = new BigNumber(NaN) - * x.isNaN() // true - * y = new BigNumber('Infinity') - * y.isNaN() // false - * ``` - */ - isNaN(): boolean; - - /** - * Returns `true` if the value of this BigNumber is negative, otherwise returns `false`. - * - * ```ts - * x = new BigNumber(-0) - * x.isNegative() // true - * y = new BigNumber(2) - * y.isNegative() // false - * ``` - */ - isNegative(): boolean; - - /** - * Returns `true` if the value of this BigNumber is positive, otherwise returns `false`. - * - * ```ts - * x = new BigNumber(-0) - * x.isPositive() // false - * y = new BigNumber(2) - * y.isPositive() // true - * ``` - */ - isPositive(): boolean; - - /** - * Returns `true` if the value of this BigNumber is zero or minus zero, otherwise returns `false`. - * - * ```ts - * x = new BigNumber(-0) - * x.isZero() // true - * ``` - */ - isZero(): boolean; - - /** - * Returns a BigNumber whose value is the value of this BigNumber minus `n`. - * - * The return value is always exact and unrounded. - * - * ```ts - * 0.3 - 0.1 // 0.19999999999999998 - * x = new BigNumber(0.3) - * x.minus(0.1) // '0.2' - * x.minus(0.6, 20) // '0' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - minus(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber modulo `n`, i.e. the integer - * remainder of dividing this BigNumber by `n`. - * - * The value returned, and in particular its sign, is dependent on the value of the `MODULO_MODE` - * setting of this BigNumber constructor. If it is 1 (default value), the result will have the - * same sign as this BigNumber, and it will match that of Javascript's `%` operator (within the - * limits of double precision) and BigDecimal's `remainder` method. - * - * The return value is always exact and unrounded. - * - * See `MODULO_MODE` for a description of the other modulo modes. - * - * ```ts - * 1 % 0.9 // 0.09999999999999998 - * x = new BigNumber(1) - * x.modulo(0.9) // '0.1' - * y = new BigNumber(33) - * y.modulo('a', 33) // '3' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - modulo(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber modulo `n`, i.e. the integer - * remainder of dividing this BigNumber by `n`. - * - * The value returned, and in particular its sign, is dependent on the value of the `MODULO_MODE` - * setting of this BigNumber constructor. If it is 1 (default value), the result will have the - * same sign as this BigNumber, and it will match that of Javascript's `%` operator (within the - * limits of double precision) and BigDecimal's `remainder` method. - * - * The return value is always exact and unrounded. - * - * See `MODULO_MODE` for a description of the other modulo modes. - * - * ```ts - * 1 % 0.9 // 0.09999999999999998 - * x = new BigNumber(1) - * x.mod(0.9) // '0.1' - * y = new BigNumber(33) - * y.mod('a', 33) // '3' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - mod(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber multiplied by `n`. - * - * The return value is always exact and unrounded. - * - * ```ts - * 0.6 * 3 // 1.7999999999999998 - * x = new BigNumber(0.6) - * y = x.multipliedBy(3) // '1.8' - * BigNumber('7e+500').multipliedBy(y) // '1.26e+501' - * x.multipliedBy('-a', 16) // '-6' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - multipliedBy(n: BigNumberValue, base?: number) : BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber multiplied by `n`. - * - * The return value is always exact and unrounded. - * - * ```ts - * 0.6 * 3 // 1.7999999999999998 - * x = new BigNumber(0.6) - * y = x.times(3) // '1.8' - * BigNumber('7e+500').times(y) // '1.26e+501' - * x.times('-a', 16) // '-6' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - times(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber negated, i.e. multiplied by -1. - * - * ```ts - * x = new BigNumber(1.8) - * x.negated() // '-1.8' - * y = new BigNumber(-1.3) - * y.negated() // '1.3' - * ``` - */ - negated(): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber plus `n`. - * - * The return value is always exact and unrounded. - * - * ```ts - * 0.1 + 0.2 // 0.30000000000000004 - * x = new BigNumber(0.1) - * y = x.plus(0.2) // '0.3' - * BigNumber(0.7).plus(x).plus(y) // '1' - * x.plus('0.1', 8) // '0.225' - * ``` - * - * @param n A numeric value. - * @param [base] The base of n. - */ - plus(n: BigNumberValue, base?: number): BigNumber; - - /** - * Returns the number of significant digits of the value of this BigNumber, or `null` if the value - * of this BigNumber is ±`Infinity` or `NaN`. - * - * If `includeZeros` is true then any trailing zeros of the integer part of the value of this - * BigNumber are counted as significant digits, otherwise they are not. - * - * Throws if `includeZeros` is invalid. - * - * ```ts - * x = new BigNumber(9876.54321) - * x.precision() // 9 - * y = new BigNumber(987000) - * y.precision(false) // 3 - * y.precision(true) // 6 - * ``` - * - * @param [includeZeros] Whether to include integer trailing zeros in the significant digit count. - */ - precision(includeZeros?: boolean): number; - - /** - * Returns a BigNumber whose value is the value of this BigNumber rounded to a precision of - * `significantDigits` significant digits using rounding mode `roundingMode`. - * - * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` will be used. - * - * Throws if `significantDigits` or `roundingMode` is invalid. - * - * ```ts - * x = new BigNumber(9876.54321) - * x.precision(6) // '9876.54' - * x.precision(6, BigNumber.ROUND_UP) // '9876.55' - * x.precision(2) // '9900' - * x.precision(2, 1) // '9800' - * x // '9876.54321' - * ``` - * - * @param significantDigits Significant digits, integer, 1 to 1e+9. - * @param [roundingMode] Rounding mode, integer, 0 to 8. - */ - precision(significantDigits: number, roundingMode?: BigNumberRoundingMode): BigNumber; - - /** - * Returns the number of significant digits of the value of this BigNumber, - * or `null` if the value of this BigNumber is ±`Infinity` or `NaN`. - * - * If `includeZeros` is true then any trailing zeros of the integer part of - * the value of this BigNumber are counted as significant digits, otherwise - * they are not. - * - * Throws if `includeZeros` is invalid. - * - * ```ts - * x = new BigNumber(9876.54321) - * x.sd() // 9 - * y = new BigNumber(987000) - * y.sd(false) // 3 - * y.sd(true) // 6 - * ``` - * - * @param [includeZeros] Whether to include integer trailing zeros in the significant digit count. - */ - sd(includeZeros?: boolean): number; - - /* - * Returns a BigNumber whose value is the value of this BigNumber rounded to a precision of - * `significantDigits` significant digits using rounding mode `roundingMode`. - * - * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` will be used. - * - * Throws if `significantDigits` or `roundingMode` is invalid. - * - * ```ts - * x = new BigNumber(9876.54321) - * x.sd(6) // '9876.54' - * x.sd(6, BigNumber.ROUND_UP) // '9876.55' - * x.sd(2) // '9900' - * x.sd(2, 1) // '9800' - * x // '9876.54321' - * ``` - * - * @param significantDigits Significant digits, integer, 1 to 1e+9. - * @param [roundingMode] Rounding mode, integer, 0 to 8. - */ - sd(significantDigits: number, roundingMode?: BigNumberRoundingMode): BigNumber; - - /** - * Returns a BigNumber whose value is the value of this BigNumber shifted by `n` places. - * - * The shift is of the decimal point, i.e. of powers of ten, and is to the left if `n` is negative - * or to the right if `n` is positive. - * - * The return value is always exact and unrounded. - * - * Throws if `n` is invalid. - * - * ```ts - * x = new BigNumber(1.23) - * x.shiftedBy(3) // '1230' - * x.shiftedBy(-3) // '0.00123' - * ``` - * - * @param n The shift value, integer, -9007199254740991 to 9007199254740991. - */ - shiftedBy(n: number): BigNumber; - - /** - * Returns a BigNumber whose value is the square root of the value of this BigNumber, rounded - * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. - * - * The return value will be correctly rounded, i.e. rounded as if the result was first calculated - * to an infinite number of correct digits before rounding. - * - * ```ts - * x = new BigNumber(16) - * x.squareRoot() // '4' - * y = new BigNumber(3) - * y.squareRoot() // '1.73205080756887729353' - * ``` - */ - squareRoot(): BigNumber; - - /** - * Returns a BigNumber whose value is the square root of the value of this BigNumber, rounded - * according to the current `DECIMAL_PLACES` and `ROUNDING_MODE` settings. - * - * The return value will be correctly rounded, i.e. rounded as if the result was first calculated - * to an infinite number of correct digits before rounding. - * - * ```ts - * x = new BigNumber(16) - * x.sqrt() // '4' - * y = new BigNumber(3) - * y.sqrt() // '1.73205080756887729353' - * ``` - */ - sqrt(): BigNumber; - - /** - * Returns a string representing the value of this BigNumber in exponential notation rounded using - * rounding mode `roundingMode` to `decimalPlaces` decimal places, i.e with one digit before the - * decimal point and `decimalPlaces` digits after it. - * - * If the value of this BigNumber in exponential notation has fewer than `decimalPlaces` fraction - * digits, the return value will be appended with zeros accordingly. - * - * If `decimalPlaces` is omitted, or is `null` or `undefined`, the number of digits after the - * decimal point defaults to the minimum number of digits necessary to represent the value - * exactly. - * - * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. - * - * Throws if `decimalPlaces` or `roundingMode` is invalid. - * - * ```ts - * x = 45.6 - * y = new BigNumber(x) - * x.toExponential() // '4.56e+1' - * y.toExponential() // '4.56e+1' - * x.toExponential(0) // '5e+1' - * y.toExponential(0) // '5e+1' - * x.toExponential(1) // '4.6e+1' - * y.toExponential(1) // '4.6e+1' - * y.toExponential(1, 1) // '4.5e+1' (ROUND_DOWN) - * x.toExponential(3) // '4.560e+1' - * y.toExponential(3) // '4.560e+1' - * ``` - * - * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. - * @param [roundingMode] Rounding mode, integer, 0 to 8. - */ - toExponential(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): string; - - /** - * Returns a string representing the value of this BigNumber in normal (fixed-point) notation - * rounded to `decimalPlaces` decimal places using rounding mode `roundingMode`. - * - * If the value of this BigNumber in normal notation has fewer than `decimalPlaces` fraction - * digits, the return value will be appended with zeros accordingly. - * - * Unlike `Number.prototype.toFixed`, which returns exponential notation if a number is greater or - * equal to 10**21, this method will always return normal notation. - * - * If `decimalPlaces` is omitted or is `null` or `undefined`, the return value will be unrounded - * and in normal notation. This is also unlike `Number.prototype.toFixed`, which returns the value - * to zero decimal places. It is useful when normal notation is required and the current - * `EXPONENTIAL_AT` setting causes `toString` to return exponential notation. - * - * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. - * - * Throws if `decimalPlaces` or `roundingMode` is invalid. - * - * ```ts - * x = 3.456 - * y = new BigNumber(x) - * x.toFixed() // '3' - * y.toFixed() // '3.456' - * y.toFixed(0) // '3' - * x.toFixed(2) // '3.46' - * y.toFixed(2) // '3.46' - * y.toFixed(2, 1) // '3.45' (ROUND_DOWN) - * x.toFixed(5) // '3.45600' - * y.toFixed(5) // '3.45600' - * ``` - * - * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. - * @param [roundingMode] Rounding mode, integer, 0 to 8. - */ - toFixed(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): string; - - /** - * Returns a string representing the value of this BigNumber in normal (fixed-point) notation - * rounded to `decimalPlaces` decimal places using rounding mode `roundingMode`, and formatted - * according to the properties of the `FORMAT` object. - * - * The properties of the `FORMAT` object are shown in the examples below. - * - * If `decimalPlaces` is omitted or is `null` or `undefined`, then the return value is not - * rounded to a fixed number of decimal places. - * - * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. - * - * Throws if `decimalPlaces` or `roundingMode` is invalid. - * - * ```ts - * format = { - * decimalSeparator: '.', - * groupSeparator: ',', - * groupSize: 3, - * secondaryGroupSize: 0, - * fractionGroupSeparator: ' ', - * fractionGroupSize: 0 - * } - * BigNumber.config({ FORMAT: format }) - * - * x = new BigNumber('123456789.123456789') - * x.toFormat() // '123,456,789.123456789' - * x.toFormat(1) // '123,456,789.1' - * - * format.groupSeparator = ' ' - * format.fractionGroupSize = 5 - * x.toFormat() // '123 456 789.12345 6789' - * - * BigNumber.config({ - * FORMAT: { - * decimalSeparator: ',', - * groupSeparator: '.', - * groupSize: 3, - * secondaryGroupSize: 2 - * } - * }) - * - * x.toFormat(6) // '12.34.56.789,123' - * ``` - * - * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. - * @param [roundingMode] Rounding mode, integer, 0 to 8. - */ - toFormat(decimalPlaces?: number, roundingMode?: BigNumberRoundingMode): string; - - /** - * Returns a string array representing the value of this BigNumber as a simple fraction with an - * integer numerator and an integer denominator. The denominator will be a positive non-zero value - * less than or equal to `max_denominator`. - * - * If a maximum denominator, `max_denominator`, is not specified, or is `null` or `undefined`, the - * denominator will be the lowest value necessary to represent the number exactly. - * - * Throws if `max_denominator` is invalid. - * - * ```ts - * x = new BigNumber(1.75) - * x.toFraction() // '7, 4' - * - * pi = new BigNumber('3.14159265358') - * pi.toFraction() // '157079632679,50000000000' - * pi.toFraction(100000) // '312689, 99532' - * pi.toFraction(10000) // '355, 113' - * pi.toFraction(100) // '311, 99' - * pi.toFraction(10) // '22, 7' - * pi.toFraction(1) // '3, 1' - * ``` - * - * @param [max_denominator] The maximum denominator, integer, >= 1 and < Infinity. - */ - toFraction(max_denominator?: BigNumberValue): BigNumber[]; - - /** - * As `valueOf`. - */ - toJSON(): string; - - /** - * Returns the value of this BigNumber as a JavaScript primitive number. - * - * Using the unary plus operator gives the same result. - * - * ```ts - * x = new BigNumber(456.789) - * x.toNumber() // 456.789 - * +x // 456.789 - * - * y = new BigNumber('45987349857634085409857349856430985') - * y.toNumber() // 4.598734985763409e+34 - * - * z = new BigNumber(-0) - * 1 / z.toNumber() // -Infinity - * 1 / +z // -Infinity - * ``` - */ - toNumber(): number; - - /** - * Returns a string representing the value of this BigNumber rounded to `significantDigits` - * significant digits using rounding mode `roundingMode`. - * - * If `significantDigits` is less than the number of digits necessary to represent the integer - * part of the value in normal (fixed-point) notation, then exponential notation is used. - * - * If `significantDigits` is omitted, or is `null` or `undefined`, then the return value is the - * same as `n.toString()`. - * - * If `roundingMode` is omitted or is `null` or `undefined`, `ROUNDING_MODE` is used. - * - * Throws if `significantDigits` or `roundingMode` is invalid. - * - * ```ts - * x = 45.6 - * y = new BigNumber(x) - * x.toPrecision() // '45.6' - * y.toPrecision() // '45.6' - * x.toPrecision(1) // '5e+1' - * y.toPrecision(1) // '5e+1' - * y.toPrecision(2, 0) // '4.6e+1' (ROUND_UP) - * y.toPrecision(2, 1) // '4.5e+1' (ROUND_DOWN) - * x.toPrecision(5) // '45.600' - * y.toPrecision(5) // '45.600' - * ``` - * - * @param [significantDigits] Significant digits, integer, 1 to 1e+9. - * @param [roundingMode] Rounding mode, integer 0 to 8. - */ - toPrecision(significantDigits?: number, roundingMode?: BigNumberRoundingMode): string; - - /** - * Returns a string representing the value of this BigNumber in base `base`, or base 10 if `base` - * is omitted or is `null` or `undefined`. - * - * For bases above 10, and using the default base conversion alphabet (see `ALPHABET`), values - * from 10 to 35 are represented by a-z (the same as `Number.prototype.toString`). - * - * If a base is specified the value is rounded according to the current `DECIMAL_PLACES` and - * `ROUNDING_MODE` settings, otherwise it is not. - * - * If a base is not specified, and this BigNumber has a positive exponent that is equal to or - * greater than the positive component of the current `EXPONENTIAL_AT` setting, or a negative - * exponent equal to or less than the negative component of the setting, then exponential notation - * is returned. - * - * If `base` is `null` or `undefined` it is ignored. - * - * Throws if `base` is invalid. - * - * ```ts - * x = new BigNumber(750000) - * x.toString() // '750000' - * BigNumber.config({ EXPONENTIAL_AT: 5 }) - * x.toString() // '7.5e+5' - * - * y = new BigNumber(362.875) - * y.toString(2) // '101101010.111' - * y.toString(9) // '442.77777777777777777778' - * y.toString(32) // 'ba.s' - * - * BigNumber.config({ DECIMAL_PLACES: 4 }); - * z = new BigNumber('1.23456789') - * z.toString() // '1.23456789' - * z.toString(10) // '1.2346' - * ``` - * - * @param [base] The base, integer, 2 to 36 (or `ALPHABET.length`, see `ALPHABET`). - */ - toString(base?: number): string; - - /** - * As `toString`, but does not accept a base argument and includes the minus sign for negative - * zero. - * - * ``ts - * x = new BigNumber('-0') - * x.toString() // '0' - * x.valueOf() // '-0' - * y = new BigNumber('1.777e+457') - * y.valueOf() // '1.777e+457' - * ``` - */ - valueOf(): string; - - /** - * Returns a new independent BigNumber constructor with configuration as described by `object`, or - * with the default configuration if object is `null` or `undefined`. - * - * Throws if `object` is not an object. - * - * ```ts - * BigNumber.config({ DECIMAL_PLACES: 5 }) - * BN = BigNumber.clone({ DECIMAL_PLACES: 9 }) - * - * x = new BigNumber(1) - * y = new BN(1) - * - * x.div(3) // 0.33333 - * y.div(3) // 0.333333333 - * - * // BN = BigNumber.clone({ DECIMAL_PLACES: 9 }) is equivalent to: - * BN = BigNumber.clone() - * BN.config({ DECIMAL_PLACES: 9 }) - * ``` - * - * @param [object] The configuration object. - */ - static clone(object?: BigNumberConfig): BigNumberConstructor; - - /** - * Configures the settings that apply to this BigNumber constructor. - * - * The configuration object, `object`, contains any number of the properties shown in the example - * below. - * - * Returns an object with the above properties and their current values. - * - * Throws if `object` is not an object, or if an invalid value is assigned to one or more of the - * properties. - * - * ```ts - * BigNumber.config({ - * DECIMAL_PLACES: 40, - * ROUNDING_MODE: BigNumber.ROUND_HALF_CEIL, - * EXPONENTIAL_AT: [-10, 20], - * RANGE: [-500, 500], - * CRYPTO: true, - * MODULO_MODE: BigNumber.ROUND_FLOOR, - * POW_PRECISION: 80, - * FORMAT: { - * groupSize: 3, - * groupSeparator: ' ', - * decimalSeparator: ',' - * }, - * ALPHABET: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_' - * }); - * - * BigNumber.config().DECIMAL_PLACES // 40 - * ``` - * - * @param object The configuration object. - */ - static config(object: BigNumberConfig): BigNumberConfig; - - /** - * Returns `true` if `value` is a BigNumber instance, otherwise returns `false`. - * - * ```ts - * x = 42 - * y = new BigNumber(x) - * - * BigNumber.isBigNumber(x) // false - * y instanceof BigNumber // true - * BigNumber.isBigNumber(y) // true - * - * BN = BigNumber.clone(); - * z = new BN(x) - * z instanceof BigNumber // false - * BigNumber.isBigNumber(z) // true - * ``` - * - * @param value The value to test. - */ - static isBigNumber(value: any): boolean; - - /** - * - * Returns a BigNumber whose value is the maximum of the arguments. - * - * Accepts either an argument list or an array of values. - * - * The return value is always exact and unrounded. - * - * ```ts - * x = new BigNumber('3257869345.0378653') - * BigNumber.maximum(4e9, x, '123456789.9') // '4000000000' - * - * arr = [12, '13', new BigNumber(14)] - * BigNumber.maximum(arr) // '14' - * ``` - * - * @param n A numeric value. - */ - static maximum(...n: BigNumberValue[]): BigNumber; - - /** - * Returns a BigNumber whose value is the maximum of the arguments. - * - * Accepts either an argument list or an array of values. - * - * The return value is always exact and unrounded. - * - * ```ts - * x = new BigNumber('3257869345.0378653') - * BigNumber.max(4e9, x, '123456789.9') // '4000000000' - * - * arr = [12, '13', new BigNumber(14)] - * BigNumber.max(arr) // '14' - * ``` - * - * @param n A numeric value. - */ - static max(...n: BigNumberValue[]): BigNumber; - - /** - * Returns a BigNumber whose value is the minimum of the arguments. - * - * Accepts either an argument list or an array of values. - * - * The return value is always exact and unrounded. - * - * ```ts - * x = new BigNumber('3257869345.0378653') - * BigNumber.minimum(4e9, x, '123456789.9') // '123456789.9' - * - * arr = [2, new BigNumber(-14), '-15.9999', -12] - * BigNumber.minimum(arr) // '-15.9999' - * ``` - * - * @param n A numeric value. - */ - static minimum(...n: BigNumberValue[]): BigNumber; - - /** - * Returns a BigNumber whose value is the minimum of the arguments. - * - * Accepts either an argument list or an array of values. - * - * The return value is always exact and unrounded. - * - * ```ts - * x = new BigNumber('3257869345.0378653') - * BigNumber.min(4e9, x, '123456789.9') // '123456789.9' - * - * arr = [2, new BigNumber(-14), '-15.9999', -12] - * BigNumber.min(arr) // '-15.9999' - * ``` - * - * @param n A numeric value. - */ - static min(...n: BigNumberValue[]): BigNumber; - - /** - * Returns a new BigNumber with a pseudo-random value equal to or greater than 0 and less than 1. - * - * The return value will have `decimalPlaces` decimal places, or less if trailing zeros are - * produced. If `decimalPlaces` is omitted, the current `DECIMAL_PLACES` setting will be used. - * - * Depending on the value of this BigNumber constructor's `CRYPTO` setting and the support for the - * `crypto` object in the host environment, the random digits of the return value are generated by - * either `Math.random` (fastest), `crypto.getRandomValues` (Web Cryptography API in recent - * browsers) or `crypto.randomBytes` (Node.js). - * - * If `CRYPTO` is true, i.e. one of the `crypto` methods is to be used, the value of a returned - * BigNumber should be cryptographically secure and statistically indistinguishable from a random - * value. - * - * Throws if `decimalPlaces` is invalid. - * - * ```ts - * BigNumber.config({ DECIMAL_PLACES: 10 }) - * BigNumber.random() // '0.4117936847' - * BigNumber.random(20) // '0.78193327636914089009' - * ``` - * - * @param [decimalPlaces] Decimal places, integer, 0 to 1e+9. - */ - static random(decimalPlaces?: number): BigNumber; - - /** - * Configures the settings that apply to this BigNumber constructor. - * - * The configuration object, `object`, contains any number of the properties shown in the example - * below. - * - * Returns an object with the above properties and their current values. - * - * Throws if `object` is not an object, or if an invalid value is assigned to one or more of the - * properties. - * - * ```ts - * BigNumber.set({ - * DECIMAL_PLACES: 40, - * ROUNDING_MODE: BigNumber.ROUND_HALF_CEIL, - * EXPONENTIAL_AT: [-10, 20], - * RANGE: [-500, 500], - * CRYPTO: true, - * MODULO_MODE: BigNumber.ROUND_FLOOR, - * POW_PRECISION: 80, - * FORMAT: { - * groupSize: 3, - * groupSeparator: ' ', - * decimalSeparator: ',' - * }, - * ALPHABET: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_' - * }); - * - * BigNumber.set().DECIMAL_PLACES // 40 - * ``` - * - * @param object The configuration object. - */ - static set(object: BigNumberConfig): BigNumberConfig; - - /** - * Helps ES6 import. - */ - private static readonly default?: BigNumberConstructor; - - /** - * Helps ES6 import. - */ - private static readonly BigNumber?: BigNumberConstructor; - - /** - * Rounds away from zero. - */ - static readonly ROUND_UP: 0; - - /** - * Rounds towards zero. - */ - static readonly ROUND_DOWN: 1; - - /** - * Rounds towards Infinity. - */ - static readonly ROUND_CEIL: 2; - - /** - * Rounds towards -Infinity. - */ - static readonly ROUND_FLOOR: 3; - - /** - * Rounds towards nearest neighbour. If equidistant, rounds away from zero . - */ - static readonly ROUND_HALF_UP: 4; - - /** - * Rounds towards nearest neighbour. If equidistant, rounds towards zero. - */ - static readonly ROUND_HALF_DOWN: 5; - - /** - * Rounds towards nearest neighbour. If equidistant, rounds towards even neighbour. - */ - static readonly ROUND_HALF_EVEN: 6; - - /** - * Rounds towards nearest neighbour. If equidistant, rounds towards Infinity. - */ - static readonly ROUND_HALF_CEIL: 7; - - /** - * Rounds towards nearest neighbour. If equidistant, rounds towards -Infinity. - */ - static readonly ROUND_HALF_FLOOR: 8; - - /** - * See `MODULO_MODE`. - */ - static readonly EUCLID: 9; -} - - -export default BigNumber; - -export namespace BigNumber { - export type Config = BigNumberConfig; - export type Constructor = BigNumberConstructor; - export type Format = BigNumberFormat; - export type Instance = BigNumberInstance; - export type ModuloMode = BigNumberModuloMode; - export type RoundingMode = BigNumberRoundingMode; - export type Value = BigNumberValue; -} - -/** - * Browsers. - */ -declare global { - const BigNumber: BigNumberConstructor; - type BigNumber = BigNumberInstance; - - namespace BigNumber { - type Config = BigNumberConfig; - type Constructor = BigNumberConstructor; - type Format = BigNumberFormat; - type Instance = BigNumberInstance; - type ModuloMode = BigNumberModuloMode; - type RoundingMode = BigNumberRoundingMode; - type Value = BigNumberValue; - } -} \ No newline at end of file diff --git a/packages/instant/test/util/dependencies/prevbignumber.js b/packages/instant/test/util/dependencies/prevbignumber.js deleted file mode 100644 index e2d3f21466..0000000000 --- a/packages/instant/test/util/dependencies/prevbignumber.js +++ /dev/null @@ -1,2705 +0,0 @@ -/* - * bignumber.js v6.0.0 - * A JavaScript library for arbitrary-precision arithmetic. - * https://github.com/MikeMcl/bignumber.js - * Copyright (c) 2018 Michael Mclaughlin - * MIT Licensed. - * - * BigNumber.prototype methods | BigNumber methods - * | - * absoluteValue abs | clone - * comparedTo | config set - * decimalPlaces dp | DECIMAL_PLACES - * dividedBy div | ROUNDING_MODE - * dividedToIntegerBy idiv | EXPONENTIAL_AT - * exponentiatedBy pow | RANGE - * integerValue | CRYPTO - * isEqualTo eq | MODULO_MODE - * isFinite | POW_PRECISION - * isGreaterThan gt | FORMAT - * isGreaterThanOrEqualTo gte | ALPHABET - * isInteger | isBigNumber - * isLessThan lt | maximum max - * isLessThanOrEqualTo lte | minimum min - * isNaN | random - * isNegative | - * isPositive | - * isZero | - * minus | - * modulo mod | - * multipliedBy times | - * negated | - * plus | - * precision sd | - * shiftedBy | - * squareRoot sqrt | - * toExponential | - * toFixed | - * toFormat | - * toFraction | - * toJSON | - * toNumber | - * toPrecision | - * toString | - * valueOf | - * - */ - - -var BigNumber, - isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i, - - mathceil = Math.ceil, - mathfloor = Math.floor, - - bignumberError = '[BigNumber Error] ', - tooManyDigits = bignumberError + 'Number primitive has more than 15 significant digits: ', - - BASE = 1e14, - LOG_BASE = 14, - MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1 - // MAX_INT32 = 0x7fffffff, // 2^31 - 1 - POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], - SQRT_BASE = 1e7, - - // EDITABLE - // The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and - // the arguments to toExponential, toFixed, toFormat, and toPrecision. - MAX = 1E9; // 0 to MAX_INT32 - - -/* - * Create and return a BigNumber constructor. - */ -function clone(configObject) { - var div, convertBase, parseNumeric, - P = BigNumber.prototype, - ONE = new BigNumber(1), - - - //----------------------------- EDITABLE CONFIG DEFAULTS ------------------------------- - - - // The default values below must be integers within the inclusive ranges stated. - // The values can also be changed at run-time using BigNumber.set. - - // The maximum number of decimal places for operations involving division. - DECIMAL_PLACES = 20, // 0 to MAX - - // The rounding mode used when rounding to the above decimal places, and when using - // toExponential, toFixed, toFormat and toPrecision, and round (default value). - // UP 0 Away from zero. - // DOWN 1 Towards zero. - // CEIL 2 Towards +Infinity. - // FLOOR 3 Towards -Infinity. - // HALF_UP 4 Towards nearest neighbour. If equidistant, up. - // HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. - // HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. - // HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. - // HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. - ROUNDING_MODE = 4, // 0 to 8 - - // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS] - - // The exponent value at and beneath which toString returns exponential notation. - // Number type: -7 - TO_EXP_NEG = -7, // 0 to -MAX - - // The exponent value at and above which toString returns exponential notation. - // Number type: 21 - TO_EXP_POS = 21, // 0 to MAX - - // RANGE : [MIN_EXP, MAX_EXP] - - // The minimum exponent value, beneath which underflow to zero occurs. - // Number type: -324 (5e-324) - MIN_EXP = -1e7, // -1 to -MAX - - // The maximum exponent value, above which overflow to Infinity occurs. - // Number type: 308 (1.7976931348623157e+308) - // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow. - MAX_EXP = 1e7, // 1 to MAX - - // Whether to use cryptographically-secure random number generation, if available. - CRYPTO = false, // true or false - - // The modulo mode used when calculating the modulus: a mod n. - // The quotient (q = a / n) is calculated according to the corresponding rounding mode. - // The remainder (r) is calculated as: r = a - n * q. - // - // UP 0 The remainder is positive if the dividend is negative, else is negative. - // DOWN 1 The remainder has the same sign as the dividend. - // This modulo mode is commonly known as 'truncated division' and is - // equivalent to (a % n) in JavaScript. - // FLOOR 3 The remainder has the same sign as the divisor (Python %). - // HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function. - // EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). - // The remainder is always positive. - // - // The truncated division, floored division, Euclidian division and IEEE 754 remainder - // modes are commonly used for the modulus operation. - // Although the other rounding modes can also be used, they may not give useful results. - MODULO_MODE = 1, // 0 to 9 - - // The maximum number of significant digits of the result of the exponentiatedBy operation. - // If POW_PRECISION is 0, there will be unlimited significant digits. - POW_PRECISION = 0, // 0 to MAX - - // The format specification used by the BigNumber.prototype.toFormat method. - FORMAT = { - decimalSeparator: '.', - groupSeparator: ',', - groupSize: 3, - secondaryGroupSize: 0, - fractionGroupSeparator: '\xA0', // non-breaking space - fractionGroupSize: 0 - }, - - // The alphabet used for base conversion. - // It must be at least 2 characters long, with no '.' or repeated character. - // '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_' - ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'; - - - //------------------------------------------------------------------------------------------ - - - // CONSTRUCTOR - - - /* - * The BigNumber constructor and exported function. - * Create and return a new instance of a BigNumber object. - * - * n {number|string|BigNumber} A numeric value. - * [b] {number} The base of n. Integer, 2 to ALPHABET.length inclusive. - */ - function BigNumber( n, b ) { - var alphabet, c, e, i, isNum, len, str, - x = this; - - // Enable constructor usage without new. - if ( !( x instanceof BigNumber ) ) { - - // Don't throw on constructor call without new (#81). - // '[BigNumber Error] Constructor call without new: {n}' - //throw Error( bignumberError + ' Constructor call without new: ' + n ); - return new BigNumber( n, b ); - } - - if ( b == null ) { - - // Duplicate. - if ( n instanceof BigNumber ) { - x.s = n.s; - x.e = n.e; - x.c = ( n = n.c ) ? n.slice() : n; - return; - } - - isNum = typeof n == 'number'; - - if ( isNum && n * 0 == 0 ) { - - // Use `1 / n` to handle minus zero also. - x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1; - - // Faster path for integers. - if ( n === ~~n ) { - for ( e = 0, i = n; i >= 10; i /= 10, e++ ); - x.e = e; - x.c = [n]; - return; - } - - str = n + ''; - } else { - if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, isNum ); - x.s = str.charCodeAt(0) == 45 ? ( str = str.slice(1), -1 ) : 1; - } - - } else { - - // '[BigNumber Error] Base {not a primitive number|not an integer|out of range}: {b}' - intCheck( b, 2, ALPHABET.length, 'Base' ); - str = n + ''; - - // Allow exponential notation to be used with base 10 argument, while - // also rounding to DECIMAL_PLACES as with other bases. - if ( b == 10 ) { - x = new BigNumber( n instanceof BigNumber ? n : str ); - return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE ); - } - - isNum = typeof n == 'number'; - - if (isNum) { - - // Avoid potential interpretation of Infinity and NaN as base 44+ values. - if ( n * 0 != 0 ) return parseNumeric( x, str, isNum, b ); - - x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1; - - // '[BigNumber Error] Number primitive has more than 15 significant digits: {n}' - if ( str.replace( /^0\.0*|\./, '' ).length > 15 ) { - throw Error - ( tooManyDigits + n ); - } - - // Prevent later check for length on converted number. - isNum = false; - } else { - x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; - - // Allow e.g. hexadecimal 'FF' as well as 'ff'. - if ( b > 10 && b < 37 ) str = str.toLowerCase(); - } - - alphabet = ALPHABET.slice( 0, b ); - e = i = 0; - - // Check that str is a valid base b number. - // Don't use RegExp so alphabet can contain special characters. - for ( len = str.length; i < len; i++ ) { - if ( alphabet.indexOf( c = str.charAt(i) ) < 0 ) { - if ( c == '.' ) { - - // If '.' is not the first character and it has not be found before. - if ( i > e ) { - e = len; - continue; - } - } - - return parseNumeric( x, n + '', isNum, b ); - } - } - - str = convertBase( str, b, 10, x.s ); - } - - // Decimal point? - if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' ); - - // Exponential form? - if ( ( i = str.search( /e/i ) ) > 0 ) { - - // Determine exponent. - if ( e < 0 ) e = i; - e += +str.slice( i + 1 ); - str = str.substring( 0, i ); - } else if ( e < 0 ) { - - // Integer. - e = str.length; - } - - // Determine leading zeros. - for ( i = 0; str.charCodeAt(i) === 48; i++ ); - - // Determine trailing zeros. - for ( len = str.length; str.charCodeAt(--len) === 48; ); - str = str.slice( i, len + 1 ); - - if (str) { - len = str.length; - - // '[BigNumber Error] Number primitive has more than 15 significant digits: {n}' - if ( isNum && len > 15 && ( n > MAX_SAFE_INTEGER || n !== mathfloor(n) ) ) { - throw Error - ( tooManyDigits + ( x.s * n ) ); - } - - e = e - i - 1; - - // Overflow? - if ( e > MAX_EXP ) { - - // Infinity. - x.c = x.e = null; - - // Underflow? - } else if ( e < MIN_EXP ) { - - // Zero. - x.c = [ x.e = 0 ]; - } else { - x.e = e; - x.c = []; - - // Transform base - - // e is the base 10 exponent. - // i is where to slice str to get the first element of the coefficient array. - i = ( e + 1 ) % LOG_BASE; - if ( e < 0 ) i += LOG_BASE; - - if ( i < len ) { - if (i) x.c.push( +str.slice( 0, i ) ); - - for ( len -= LOG_BASE; i < len; ) { - x.c.push( +str.slice( i, i += LOG_BASE ) ); - } - - str = str.slice(i); - i = LOG_BASE - str.length; - } else { - i -= len; - } - - for ( ; i--; str += '0' ); - x.c.push( +str ); - } - } else { - - // Zero. - x.c = [ x.e = 0 ]; - } - } - - - // CONSTRUCTOR PROPERTIES - - - BigNumber.clone = clone; - - BigNumber.ROUND_UP = 0; - BigNumber.ROUND_DOWN = 1; - BigNumber.ROUND_CEIL = 2; - BigNumber.ROUND_FLOOR = 3; - BigNumber.ROUND_HALF_UP = 4; - BigNumber.ROUND_HALF_DOWN = 5; - BigNumber.ROUND_HALF_EVEN = 6; - BigNumber.ROUND_HALF_CEIL = 7; - BigNumber.ROUND_HALF_FLOOR = 8; - BigNumber.EUCLID = 9; - - - /* - * Configure infrequently-changing library-wide settings. - * - * Accept an object with the following optional properties (if the value of a property is - * a number, it must be an integer within the inclusive range stated): - * - * DECIMAL_PLACES {number} 0 to MAX - * ROUNDING_MODE {number} 0 to 8 - * EXPONENTIAL_AT {number|number[]} -MAX to MAX or [-MAX to 0, 0 to MAX] - * RANGE {number|number[]} -MAX to MAX (not zero) or [-MAX to -1, 1 to MAX] - * CRYPTO {boolean} true or false - * MODULO_MODE {number} 0 to 9 - * POW_PRECISION {number} 0 to MAX - * ALPHABET {string} A string of two or more unique characters, and not - * containing '.'. The empty string, null or undefined - * resets the alphabet to its default value. - * FORMAT {object} An object with some of the following properties: - * decimalSeparator {string} - * groupSeparator {string} - * groupSize {number} - * secondaryGroupSize {number} - * fractionGroupSeparator {string} - * fractionGroupSize {number} - * - * (The values assigned to the above FORMAT object properties are not checked for validity.) - * - * E.g. - * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 }) - * - * Ignore properties/parameters set to null or undefined, except for ALPHABET. - * - * Return an object with the properties current values. - */ - BigNumber.config = BigNumber.set = function (obj) { - var p, v; - - if ( obj != null ) { - - if ( typeof obj == 'object' ) { - - // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive. - // '[BigNumber Error] DECIMAL_PLACES {not a primitive number|not an integer|out of range}: {v}' - if ( obj.hasOwnProperty( p = 'DECIMAL_PLACES' ) ) { - v = obj[p]; - intCheck( v, 0, MAX, p ); - DECIMAL_PLACES = v; - } - - // ROUNDING_MODE {number} Integer, 0 to 8 inclusive. - // '[BigNumber Error] ROUNDING_MODE {not a primitive number|not an integer|out of range}: {v}' - if ( obj.hasOwnProperty( p = 'ROUNDING_MODE' ) ) { - v = obj[p]; - intCheck( v, 0, 8, p ); - ROUNDING_MODE = v; - } - - // EXPONENTIAL_AT {number|number[]} - // Integer, -MAX to MAX inclusive or - // [integer -MAX to 0 inclusive, 0 to MAX inclusive]. - // '[BigNumber Error] EXPONENTIAL_AT {not a primitive number|not an integer|out of range}: {v}' - if ( obj.hasOwnProperty( p = 'EXPONENTIAL_AT' ) ) { - v = obj[p]; - if ( isArray(v) ) { - intCheck( v[0], -MAX, 0, p ); - intCheck( v[1], 0, MAX, p ); - TO_EXP_NEG = v[0]; - TO_EXP_POS = v[1]; - } else { - intCheck( v, -MAX, MAX, p ); - TO_EXP_NEG = -( TO_EXP_POS = v < 0 ? -v : v ); - } - } - - // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or - // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive]. - // '[BigNumber Error] RANGE {not a primitive number|not an integer|out of range|cannot be zero}: {v}' - if ( obj.hasOwnProperty( p = 'RANGE' ) ) { - v = obj[p]; - if ( isArray(v) ) { - intCheck( v[0], -MAX, -1, p ); - intCheck( v[1], 1, MAX, p ); - MIN_EXP = v[0]; - MAX_EXP = v[1]; - } else { - intCheck( v, -MAX, MAX, p ); - if (v) { - MIN_EXP = -( MAX_EXP = v < 0 ? -v : v ); - } else { - throw Error - ( bignumberError + p + ' cannot be zero: ' + v ); - } - } - } - - // CRYPTO {boolean} true or false. - // '[BigNumber Error] CRYPTO not true or false: {v}' - // '[BigNumber Error] crypto unavailable' - if ( obj.hasOwnProperty( p = 'CRYPTO' ) ) { - v = obj[p]; - if ( v === !!v ) { - if (v) { - if ( typeof crypto != 'undefined' && crypto && - (crypto.getRandomValues || crypto.randomBytes) ) { - CRYPTO = v; - } else { - CRYPTO = !v; - throw Error - ( bignumberError + 'crypto unavailable' ); - } - } else { - CRYPTO = v; - } - } else { - throw Error - ( bignumberError + p + ' not true or false: ' + v ); - } - } - - // MODULO_MODE {number} Integer, 0 to 9 inclusive. - // '[BigNumber Error] MODULO_MODE {not a primitive number|not an integer|out of range}: {v}' - if ( obj.hasOwnProperty( p = 'MODULO_MODE' ) ) { - v = obj[p]; - intCheck( v, 0, 9, p ); - MODULO_MODE = v; - } - - // POW_PRECISION {number} Integer, 0 to MAX inclusive. - // '[BigNumber Error] POW_PRECISION {not a primitive number|not an integer|out of range}: {v}' - if ( obj.hasOwnProperty( p = 'POW_PRECISION' ) ) { - v = obj[p]; - intCheck( v, 0, MAX, p ); - POW_PRECISION = v; - } - - // FORMAT {object} - // '[BigNumber Error] FORMAT not an object: {v}' - if ( obj.hasOwnProperty( p = 'FORMAT' ) ) { - v = obj[p]; - if ( typeof v == 'object' ) FORMAT = v; - else throw Error - ( bignumberError + p + ' not an object: ' + v ); - } - - // ALPHABET {string} - // '[BigNumber Error] ALPHABET invalid: {v}' - if ( obj.hasOwnProperty( p = 'ALPHABET' ) ) { - v = obj[p]; - - // Disallow if only one character, or contains '.' or a repeated character. - if ( typeof v == 'string' && !/^.$|\.|(.).*\1/.test(v) ) { - ALPHABET = v; - } else { - throw Error - ( bignumberError + p + ' invalid: ' + v ); - } - } - - } else { - - // '[BigNumber Error] Object expected: {v}' - throw Error - ( bignumberError + 'Object expected: ' + obj ); - } - } - - return { - DECIMAL_PLACES: DECIMAL_PLACES, - ROUNDING_MODE: ROUNDING_MODE, - EXPONENTIAL_AT: [ TO_EXP_NEG, TO_EXP_POS ], - RANGE: [ MIN_EXP, MAX_EXP ], - CRYPTO: CRYPTO, - MODULO_MODE: MODULO_MODE, - POW_PRECISION: POW_PRECISION, - FORMAT: FORMAT, - ALPHABET: ALPHABET - }; - }; - - - /* - * Return true if v is a BigNumber instance, otherwise return false. - * - * v {any} - */ - BigNumber.isBigNumber = function (v) { - return v instanceof BigNumber || v && v._isBigNumber === true || false; - }; - - - /* - * Return a new BigNumber whose value is the maximum of the arguments. - * - * arguments {number|string|BigNumber} - */ - BigNumber.maximum = BigNumber.max = function () { - return maxOrMin( arguments, P.lt ); - }; - - - /* - * Return a new BigNumber whose value is the minimum of the arguments. - * - * arguments {number|string|BigNumber} - */ - BigNumber.minimum = BigNumber.min = function () { - return maxOrMin( arguments, P.gt ); - }; - - - /* - * Return a new BigNumber with a random value equal to or greater than 0 and less than 1, - * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing - * zeros are produced). - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp}' - * '[BigNumber Error] crypto unavailable' - */ - BigNumber.random = (function () { - var pow2_53 = 0x20000000000000; - - // Return a 53 bit integer n, where 0 <= n < 9007199254740992. - // Check if Math.random() produces more than 32 bits of randomness. - // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits. - // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1. - var random53bitInt = (Math.random() * pow2_53) & 0x1fffff - ? function () { return mathfloor( Math.random() * pow2_53 ); } - : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) + - (Math.random() * 0x800000 | 0); }; - - return function (dp) { - var a, b, e, k, v, - i = 0, - c = [], - rand = new BigNumber(ONE); - - if ( dp == null ) dp = DECIMAL_PLACES; - else intCheck( dp, 0, MAX ); - - k = mathceil( dp / LOG_BASE ); - - if (CRYPTO) { - - // Browsers supporting crypto.getRandomValues. - if (crypto.getRandomValues) { - - a = crypto.getRandomValues( new Uint32Array( k *= 2 ) ); - - for ( ; i < k; ) { - - // 53 bits: - // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2) - // 11111 11111111 11111111 11111111 11100000 00000000 00000000 - // ((Math.pow(2, 32) - 1) >>> 11).toString(2) - // 11111 11111111 11111111 - // 0x20000 is 2^21. - v = a[i] * 0x20000 + (a[i + 1] >>> 11); - - // Rejection sampling: - // 0 <= v < 9007199254740992 - // Probability that v >= 9e15, is - // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251 - if ( v >= 9e15 ) { - b = crypto.getRandomValues( new Uint32Array(2) ); - a[i] = b[0]; - a[i + 1] = b[1]; - } else { - - // 0 <= v <= 8999999999999999 - // 0 <= (v % 1e14) <= 99999999999999 - c.push( v % 1e14 ); - i += 2; - } - } - i = k / 2; - - // Node.js supporting crypto.randomBytes. - } else if (crypto.randomBytes) { - - // buffer - a = crypto.randomBytes( k *= 7 ); - - for ( ; i < k; ) { - - // 0x1000000000000 is 2^48, 0x10000000000 is 2^40 - // 0x100000000 is 2^32, 0x1000000 is 2^24 - // 11111 11111111 11111111 11111111 11111111 11111111 11111111 - // 0 <= v < 9007199254740992 - v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) + - ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) + - ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6]; - - if ( v >= 9e15 ) { - crypto.randomBytes(7).copy( a, i ); - } else { - - // 0 <= (v % 1e14) <= 99999999999999 - c.push( v % 1e14 ); - i += 7; - } - } - i = k / 7; - } else { - CRYPTO = false; - throw Error - ( bignumberError + 'crypto unavailable' ); - } - } - - // Use Math.random. - if (!CRYPTO) { - - for ( ; i < k; ) { - v = random53bitInt(); - if ( v < 9e15 ) c[i++] = v % 1e14; - } - } - - k = c[--i]; - dp %= LOG_BASE; - - // Convert trailing digits to zeros according to dp. - if ( k && dp ) { - v = POWS_TEN[LOG_BASE - dp]; - c[i] = mathfloor( k / v ) * v; - } - - // Remove trailing elements which are zero. - for ( ; c[i] === 0; c.pop(), i-- ); - - // Zero? - if ( i < 0 ) { - c = [ e = 0 ]; - } else { - - // Remove leading elements which are zero and adjust exponent accordingly. - for ( e = -1 ; c[0] === 0; c.splice(0, 1), e -= LOG_BASE); - - // Count the digits of the first element of c to determine leading zeros, and... - for ( i = 1, v = c[0]; v >= 10; v /= 10, i++); - - // adjust the exponent accordingly. - if ( i < LOG_BASE ) e -= LOG_BASE - i; - } - - rand.e = e; - rand.c = c; - return rand; - }; - })(); - - - // PRIVATE FUNCTIONS - - - // Called by BigNumber and BigNumber.prototype.toString. - convertBase = ( function () { - var decimal = '0123456789'; - - /* - * Convert string of baseIn to an array of numbers of baseOut. - * Eg. toBaseOut('255', 10, 16) returns [15, 15]. - * Eg. toBaseOut('ff', 16, 10) returns [2, 5, 5]. - */ - function toBaseOut( str, baseIn, baseOut, alphabet ) { - var j, - arr = [0], - arrL, - i = 0, - len = str.length; - - for ( ; i < len; ) { - for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn ); - - arr[0] += alphabet.indexOf( str.charAt( i++ ) ); - - for ( j = 0; j < arr.length; j++ ) { - - if ( arr[j] > baseOut - 1 ) { - if ( arr[j + 1] == null ) arr[j + 1] = 0; - arr[j + 1] += arr[j] / baseOut | 0; - arr[j] %= baseOut; - } - } - } - - return arr.reverse(); - } - - // Convert a numeric string of baseIn to a numeric string of baseOut. - // If the caller is toString, we are converting from base 10 to baseOut. - // If the caller is BigNumber, we are converting from baseIn to base 10. - return function ( str, baseIn, baseOut, sign, callerIsToString ) { - var alphabet, d, e, k, r, x, xc, y, - i = str.indexOf( '.' ), - dp = DECIMAL_PLACES, - rm = ROUNDING_MODE; - - // Non-integer. - if ( i >= 0 ) { - k = POW_PRECISION; - - // Unlimited precision. - POW_PRECISION = 0; - str = str.replace( '.', '' ); - y = new BigNumber(baseIn); - x = y.pow( str.length - i ); - POW_PRECISION = k; - - // Convert str as if an integer, then restore the fraction part by dividing the - // result by its base raised to a power. - - y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e, '0' ), - 10, baseOut, decimal ); - y.e = y.c.length; - } - - // Convert the number as integer. - - xc = toBaseOut( str, baseIn, baseOut, callerIsToString - ? ( alphabet = ALPHABET, decimal ) - : ( alphabet = decimal, ALPHABET ) ); - - - // xc now represents str as an integer and converted to baseOut. e is the exponent. - e = k = xc.length; - - // Remove trailing zeros. - for ( ; xc[--k] == 0; xc.pop() ); - - // Zero? - if ( !xc[0] ) return alphabet.charAt(0); - - // Does str represent an integer? If so, no need for the division. - if ( i < 0 ) { - --e; - } else { - x.c = xc; - x.e = e; - - // The sign is needed for correct rounding. - x.s = sign; - x = div( x, y, dp, rm, baseOut ); - xc = x.c; - r = x.r; - e = x.e; - } - - // xc now represents str converted to baseOut. - - // THe index of the rounding digit. - d = e + dp + 1; - - // The rounding digit: the digit to the right of the digit that may be rounded up. - i = xc[d]; - - // Look at the rounding digits and mode to determine whether to round up. - - k = baseOut / 2; - r = r || d < 0 || xc[d + 1] != null; - - r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) - : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 || - rm == ( x.s < 0 ? 8 : 7 ) ); - - // If the index of the rounding digit is not greater than zero, or xc represents - // zero, then the result of the base conversion is zero or, if rounding up, a value - // such as 0.00001. - if ( d < 1 || !xc[0] ) { - - // 1^-dp or 0 - str = r ? toFixedPoint( alphabet.charAt(1), -dp, alphabet.charAt(0) ) - : alphabet.charAt(0); - } else { - - // Truncate xc to the required number of decimal places. - xc.length = d; - - // Round up? - if (r) { - - // Rounding up may mean the previous digit has to be rounded up and so on. - for ( --baseOut; ++xc[--d] > baseOut; ) { - xc[d] = 0; - - if ( !d ) { - ++e; - xc = [1].concat(xc); - } - } - } - - // Determine trailing zeros. - for ( k = xc.length; !xc[--k]; ); - - // E.g. [4, 11, 15] becomes 4bf. - for ( i = 0, str = ''; i <= k; str += alphabet.charAt( xc[i++] ) ); - - // Add leading zeros, decimal point and trailing zeros as required. - str = toFixedPoint( str, e, alphabet.charAt(0) ); - } - - // The caller will add the sign. - return str; - }; - })(); - - - // Perform division in the specified base. Called by div and convertBase. - div = (function () { - - // Assume non-zero x and k. - function multiply( x, k, base ) { - var m, temp, xlo, xhi, - carry = 0, - i = x.length, - klo = k % SQRT_BASE, - khi = k / SQRT_BASE | 0; - - for ( x = x.slice(); i--; ) { - xlo = x[i] % SQRT_BASE; - xhi = x[i] / SQRT_BASE | 0; - m = khi * xlo + xhi * klo; - temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry; - carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi; - x[i] = temp % base; - } - - if (carry) x = [carry].concat(x); - - return x; - } - - function compare( a, b, aL, bL ) { - var i, cmp; - - if ( aL != bL ) { - cmp = aL > bL ? 1 : -1; - } else { - - for ( i = cmp = 0; i < aL; i++ ) { - - if ( a[i] != b[i] ) { - cmp = a[i] > b[i] ? 1 : -1; - break; - } - } - } - return cmp; - } - - function subtract( a, b, aL, base ) { - var i = 0; - - // Subtract b from a. - for ( ; aL--; ) { - a[aL] -= i; - i = a[aL] < b[aL] ? 1 : 0; - a[aL] = i * base + a[aL] - b[aL]; - } - - // Remove leading zeros. - for ( ; !a[0] && a.length > 1; a.splice(0, 1) ); - } - - // x: dividend, y: divisor. - return function ( x, y, dp, rm, base ) { - var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0, - yL, yz, - s = x.s == y.s ? 1 : -1, - xc = x.c, - yc = y.c; - - // Either NaN, Infinity or 0? - if ( !xc || !xc[0] || !yc || !yc[0] ) { - - return new BigNumber( - - // Return NaN if either NaN, or both Infinity or 0. - !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN : - - // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0. - xc && xc[0] == 0 || !yc ? s * 0 : s / 0 - ); - } - - q = new BigNumber(s); - qc = q.c = []; - e = x.e - y.e; - s = dp + e + 1; - - if ( !base ) { - base = BASE; - e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE ); - s = s / LOG_BASE | 0; - } - - // Result exponent may be one less then the current value of e. - // The coefficients of the BigNumbers from convertBase may have trailing zeros. - for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ ); - - if ( yc[i] > ( xc[i] || 0 ) ) e--; - - if ( s < 0 ) { - qc.push(1); - more = true; - } else { - xL = xc.length; - yL = yc.length; - i = 0; - s += 2; - - // Normalise xc and yc so highest order digit of yc is >= base / 2. - - n = mathfloor( base / ( yc[0] + 1 ) ); - - // Not necessary, but to handle odd bases where yc[0] == ( base / 2 ) - 1. - // if ( n > 1 || n++ == 1 && yc[0] < base / 2 ) { - if ( n > 1 ) { - yc = multiply( yc, n, base ); - xc = multiply( xc, n, base ); - yL = yc.length; - xL = xc.length; - } - - xi = yL; - rem = xc.slice( 0, yL ); - remL = rem.length; - - // Add zeros to make remainder as long as divisor. - for ( ; remL < yL; rem[remL++] = 0 ); - yz = yc.slice(); - yz = [0].concat(yz); - yc0 = yc[0]; - if ( yc[1] >= base / 2 ) yc0++; - // Not necessary, but to prevent trial digit n > base, when using base 3. - // else if ( base == 3 && yc0 == 1 ) yc0 = 1 + 1e-15; - - do { - n = 0; - - // Compare divisor and remainder. - cmp = compare( yc, rem, yL, remL ); - - // If divisor < remainder. - if ( cmp < 0 ) { - - // Calculate trial digit, n. - - rem0 = rem[0]; - if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 ); - - // n is how many times the divisor goes into the current remainder. - n = mathfloor( rem0 / yc0 ); - - // Algorithm: - // 1. product = divisor * trial digit (n) - // 2. if product > remainder: product -= divisor, n-- - // 3. remainder -= product - // 4. if product was < remainder at 2: - // 5. compare new remainder and divisor - // 6. If remainder > divisor: remainder -= divisor, n++ - - if ( n > 1 ) { - - // n may be > base only when base is 3. - if (n >= base) n = base - 1; - - // product = divisor * trial digit. - prod = multiply( yc, n, base ); - prodL = prod.length; - remL = rem.length; - - // Compare product and remainder. - // If product > remainder. - // Trial digit n too high. - // n is 1 too high about 5% of the time, and is not known to have - // ever been more than 1 too high. - while ( compare( prod, rem, prodL, remL ) == 1 ) { - n--; - - // Subtract divisor from product. - subtract( prod, yL < prodL ? yz : yc, prodL, base ); - prodL = prod.length; - cmp = 1; - } - } else { - - // n is 0 or 1, cmp is -1. - // If n is 0, there is no need to compare yc and rem again below, - // so change cmp to 1 to avoid it. - // If n is 1, leave cmp as -1, so yc and rem are compared again. - if ( n == 0 ) { - - // divisor < remainder, so n must be at least 1. - cmp = n = 1; - } - - // product = divisor - prod = yc.slice(); - prodL = prod.length; - } - - if ( prodL < remL ) prod = [0].concat(prod); - - // Subtract product from remainder. - subtract( rem, prod, remL, base ); - remL = rem.length; - - // If product was < remainder. - if ( cmp == -1 ) { - - // Compare divisor and new remainder. - // If divisor < new remainder, subtract divisor from remainder. - // Trial digit n too low. - // n is 1 too low about 5% of the time, and very rarely 2 too low. - while ( compare( yc, rem, yL, remL ) < 1 ) { - n++; - - // Subtract divisor from remainder. - subtract( rem, yL < remL ? yz : yc, remL, base ); - remL = rem.length; - } - } - } else if ( cmp === 0 ) { - n++; - rem = [0]; - } // else cmp === 1 and n will be 0 - - // Add the next digit, n, to the result array. - qc[i++] = n; - - // Update the remainder. - if ( rem[0] ) { - rem[remL++] = xc[xi] || 0; - } else { - rem = [ xc[xi] ]; - remL = 1; - } - } while ( ( xi++ < xL || rem[0] != null ) && s-- ); - - more = rem[0] != null; - - // Leading zero? - if ( !qc[0] ) qc.splice(0, 1); - } - - if ( base == BASE ) { - - // To calculate q.e, first get the number of digits of qc[0]. - for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ ); - - round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more ); - - // Caller is convertBase. - } else { - q.e = e; - q.r = +more; - } - - return q; - }; - })(); - - - /* - * Return a string representing the value of BigNumber n in fixed-point or exponential - * notation rounded to the specified decimal places or significant digits. - * - * n: a BigNumber. - * i: the index of the last digit required (i.e. the digit that may be rounded up). - * rm: the rounding mode. - * id: 1 (toExponential) or 2 (toPrecision). - */ - function format( n, i, rm, id ) { - var c0, e, ne, len, str; - - if ( rm == null ) rm = ROUNDING_MODE; - else intCheck( rm, 0, 8 ); - - if ( !n.c ) return n.toString(); - - c0 = n.c[0]; - ne = n.e; - - if ( i == null ) { - str = coeffToString( n.c ); - str = id == 1 || id == 2 && ne <= TO_EXP_NEG - ? toExponential( str, ne ) - : toFixedPoint( str, ne, '0' ); - } else { - n = round( new BigNumber(n), i, rm ); - - // n.e may have changed if the value was rounded up. - e = n.e; - - str = coeffToString( n.c ); - len = str.length; - - // toPrecision returns exponential notation if the number of significant digits - // specified is less than the number of digits necessary to represent the integer - // part of the value in fixed-point notation. - - // Exponential notation. - if ( id == 1 || id == 2 && ( i <= e || e <= TO_EXP_NEG ) ) { - - // Append zeros? - for ( ; len < i; str += '0', len++ ); - str = toExponential( str, e ); - - // Fixed-point notation. - } else { - i -= ne; - str = toFixedPoint( str, e, '0' ); - - // Append zeros? - if ( e + 1 > len ) { - if ( --i > 0 ) for ( str += '.'; i--; str += '0' ); - } else { - i += e - len; - if ( i > 0 ) { - if ( e + 1 == len ) str += '.'; - for ( ; i--; str += '0' ); - } - } - } - } - - return n.s < 0 && c0 ? '-' + str : str; - } - - - // Handle BigNumber.max and BigNumber.min. - function maxOrMin( args, method ) { - var m, n, - i = 0; - - if ( isArray( args[0] ) ) args = args[0]; - m = new BigNumber( args[0] ); - - for ( ; ++i < args.length; ) { - n = new BigNumber( args[i] ); - - // If any number is NaN, return NaN. - if ( !n.s ) { - m = n; - break; - } else if ( method.call( m, n ) ) { - m = n; - } - } - - return m; - } - - - /* - * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP. - * Called by minus, plus and times. - */ - function normalise( n, c, e ) { - var i = 1, - j = c.length; - - // Remove trailing zeros. - for ( ; !c[--j]; c.pop() ); - - // Calculate the base 10 exponent. First get the number of digits of c[0]. - for ( j = c[0]; j >= 10; j /= 10, i++ ); - - // Overflow? - if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) { - - // Infinity. - n.c = n.e = null; - - // Underflow? - } else if ( e < MIN_EXP ) { - - // Zero. - n.c = [ n.e = 0 ]; - } else { - n.e = e; - n.c = c; - } - - return n; - } - - - // Handle values that fail the validity test in BigNumber. - parseNumeric = (function () { - var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, - dotAfter = /^([^.]+)\.$/, - dotBefore = /^\.([^.]+)$/, - isInfinityOrNaN = /^-?(Infinity|NaN)$/, - whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g; - - return function ( x, str, isNum, b ) { - var base, - s = isNum ? str : str.replace( whitespaceOrPlus, '' ); - - // No exception on ±Infinity or NaN. - if ( isInfinityOrNaN.test(s) ) { - x.s = isNaN(s) ? null : s < 0 ? -1 : 1; - x.c = x.e = null; - } else { - if ( !isNum ) { - - // basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i - s = s.replace( basePrefix, function ( m, p1, p2 ) { - base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8; - return !b || b == base ? p1 : m; - }); - - if (b) { - base = b; - - // E.g. '1.' to '1', '.1' to '0.1' - s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' ); - } - - if ( str != s ) return new BigNumber( s, base ); - } - - // '[BigNumber Error] Not a number: {n}' - // '[BigNumber Error] Not a base {b} number: {n}' - throw Error - ( bignumberError + 'Not a' + ( b ? ' base ' + b : '' ) + ' number: ' + str ); - } - } - })(); - - - /* - * Round x to sd significant digits using rounding mode rm. Check for over/under-flow. - * If r is truthy, it is known that there are more digits after the rounding digit. - */ - function round( x, sd, rm, r ) { - var d, i, j, k, n, ni, rd, - xc = x.c, - pows10 = POWS_TEN; - - // if x is not Infinity or NaN... - if (xc) { - - // rd is the rounding digit, i.e. the digit after the digit that may be rounded up. - // n is a base 1e14 number, the value of the element of array x.c containing rd. - // ni is the index of n within x.c. - // d is the number of digits of n. - // i is the index of rd within n including leading zeros. - // j is the actual index of rd within n (if < 0, rd is a leading zero). - out: { - - // Get the number of digits of the first element of xc. - for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ ); - i = sd - d; - - // If the rounding digit is in the first element of xc... - if ( i < 0 ) { - i += LOG_BASE; - j = sd; - n = xc[ ni = 0 ]; - - // Get the rounding digit at index j of n. - rd = n / pows10[ d - j - 1 ] % 10 | 0; - } else { - ni = mathceil( ( i + 1 ) / LOG_BASE ); - - if ( ni >= xc.length ) { - - if (r) { - - // Needed by sqrt. - for ( ; xc.length <= ni; xc.push(0) ); - n = rd = 0; - d = 1; - i %= LOG_BASE; - j = i - LOG_BASE + 1; - } else { - break out; - } - } else { - n = k = xc[ni]; - - // Get the number of digits of n. - for ( d = 1; k >= 10; k /= 10, d++ ); - - // Get the index of rd within n. - i %= LOG_BASE; - - // Get the index of rd within n, adjusted for leading zeros. - // The number of leading zeros of n is given by LOG_BASE - d. - j = i - LOG_BASE + d; - - // Get the rounding digit at index j of n. - rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0; - } - } - - r = r || sd < 0 || - - // Are there any non-zero digits after the rounding digit? - // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right - // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714. - xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] ); - - r = rm < 4 - ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) - : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 && - - // Check whether the digit to the left of the rounding digit is odd. - ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 || - rm == ( x.s < 0 ? 8 : 7 ) ); - - if ( sd < 1 || !xc[0] ) { - xc.length = 0; - - if (r) { - - // Convert sd to decimal places. - sd -= x.e + 1; - - // 1, 0.1, 0.01, 0.001, 0.0001 etc. - xc[0] = pows10[ ( LOG_BASE - sd % LOG_BASE ) % LOG_BASE ]; - x.e = -sd || 0; - } else { - - // Zero. - xc[0] = x.e = 0; - } - - return x; - } - - // Remove excess digits. - if ( i == 0 ) { - xc.length = ni; - k = 1; - ni--; - } else { - xc.length = ni + 1; - k = pows10[ LOG_BASE - i ]; - - // E.g. 56700 becomes 56000 if 7 is the rounding digit. - // j > 0 means i > number of leading zeros of n. - xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0; - } - - // Round up? - if (r) { - - for ( ; ; ) { - - // If the digit to be rounded up is in the first element of xc... - if ( ni == 0 ) { - - // i will be the length of xc[0] before k is added. - for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ ); - j = xc[0] += k; - for ( k = 1; j >= 10; j /= 10, k++ ); - - // if i != k the length has increased. - if ( i != k ) { - x.e++; - if ( xc[0] == BASE ) xc[0] = 1; - } - - break; - } else { - xc[ni] += k; - if ( xc[ni] != BASE ) break; - xc[ni--] = 0; - k = 1; - } - } - } - - // Remove trailing zeros. - for ( i = xc.length; xc[--i] === 0; xc.pop() ); - } - - // Overflow? Infinity. - if ( x.e > MAX_EXP ) { - x.c = x.e = null; - - // Underflow? Zero. - } else if ( x.e < MIN_EXP ) { - x.c = [ x.e = 0 ]; - } - } - - return x; - } - - - // PROTOTYPE/INSTANCE METHODS - - - /* - * Return a new BigNumber whose value is the absolute value of this BigNumber. - */ - P.absoluteValue = P.abs = function () { - var x = new BigNumber(this); - if ( x.s < 0 ) x.s = 1; - return x; - }; - - - /* - * Return - * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b), - * -1 if the value of this BigNumber is less than the value of BigNumber(y, b), - * 0 if they have the same value, - * or null if the value of either is NaN. - */ - P.comparedTo = function ( y, b ) { - return compare( this, new BigNumber( y, b ) ); - }; - - - /* - * If dp is undefined or null or true or false, return the number of decimal places of the - * value of this BigNumber, or null if the value of this BigNumber is ±Infinity or NaN. - * - * Otherwise, if dp is a number, return a new BigNumber whose value is the value of this - * BigNumber rounded to a maximum of dp decimal places using rounding mode rm, or - * ROUNDING_MODE if rm is omitted. - * - * [dp] {number} Decimal places: integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' - */ - P.decimalPlaces = P.dp = function ( dp, rm ) { - var c, n, v, - x = this; - - if ( dp != null ) { - intCheck( dp, 0, MAX ); - if ( rm == null ) rm = ROUNDING_MODE; - else intCheck( rm, 0, 8 ); - - return round( new BigNumber(x), dp + x.e + 1, rm ); - } - - if ( !( c = x.c ) ) return null; - n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE; - - // Subtract the number of trailing zeros of the last number. - if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- ); - if ( n < 0 ) n = 0; - - return n; - }; - - - /* - * n / 0 = I - * n / N = N - * n / I = 0 - * 0 / n = 0 - * 0 / 0 = N - * 0 / N = N - * 0 / I = 0 - * N / n = N - * N / 0 = N - * N / N = N - * N / I = N - * I / n = I - * I / 0 = I - * I / N = N - * I / I = N - * - * Return a new BigNumber whose value is the value of this BigNumber divided by the value of - * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE. - */ - P.dividedBy = P.div = function ( y, b ) { - return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE ); - }; - - - /* - * Return a new BigNumber whose value is the integer part of dividing the value of this - * BigNumber by the value of BigNumber(y, b). - */ - P.dividedToIntegerBy = P.idiv = function ( y, b ) { - return div( this, new BigNumber( y, b ), 0, 1 ); - }; - - - /* - * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b), - * otherwise return false. - */ - P.isEqualTo = P.eq = function ( y, b ) { - return compare( this, new BigNumber( y, b ) ) === 0; - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber rounded to an integer - * using rounding mode rm, or ROUNDING_MODE if rm is omitted. - * - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {rm}' - */ - P.integerValue = function (rm) { - var n = new BigNumber(this); - if ( rm == null ) rm = ROUNDING_MODE; - else intCheck( rm, 0, 8 ); - return round( n, n.e + 1, rm ); - }; - - - /* - * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b), - * otherwise return false. - */ - P.isGreaterThan = P.gt = function ( y, b ) { - return compare( this, new BigNumber( y, b ) ) > 0; - }; - - - /* - * Return true if the value of this BigNumber is greater than or equal to the value of - * BigNumber(y, b), otherwise return false. - */ - P.isGreaterThanOrEqualTo = P.gte = function ( y, b ) { - return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0; - - }; - - - /* - * Return true if the value of this BigNumber is a finite number, otherwise return false. - */ - P.isFinite = function () { - return !!this.c; - }; - - - /* - * Return true if the value of this BigNumber is an integer, otherwise return false. - */ - P.isInteger = function () { - return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2; - }; - - - /* - * Return true if the value of this BigNumber is NaN, otherwise return false. - */ - P.isNaN = function () { - return !this.s; - }; - - - /* - * Return true if the value of this BigNumber is negative, otherwise return false. - */ - P.isNegative = function () { - return this.s < 0; - }; - - - /* - * Return true if the value of this BigNumber is positive, otherwise return false. - */ - P.isPositive = function () { - return this.s > 0; - }; - - - /* - * Return true if the value of this BigNumber is 0 or -0, otherwise return false. - */ - P.isZero = function () { - return !!this.c && this.c[0] == 0; - }; - - - /* - * Return true if the value of this BigNumber is less than the value of BigNumber(y, b), - * otherwise return false. - */ - P.isLessThan = P.lt = function ( y, b ) { - return compare( this, new BigNumber( y, b ) ) < 0; - }; - - - /* - * Return true if the value of this BigNumber is less than or equal to the value of - * BigNumber(y, b), otherwise return false. - */ - P.isLessThanOrEqualTo = P.lte = function ( y, b ) { - return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0; - }; - - - /* - * n - 0 = n - * n - N = N - * n - I = -I - * 0 - n = -n - * 0 - 0 = 0 - * 0 - N = N - * 0 - I = -I - * N - n = N - * N - 0 = N - * N - N = N - * N - I = N - * I - n = I - * I - 0 = I - * I - N = N - * I - I = N - * - * Return a new BigNumber whose value is the value of this BigNumber minus the value of - * BigNumber(y, b). - */ - P.minus = function ( y, b ) { - var i, j, t, xLTy, - x = this, - a = x.s; - - y = new BigNumber( y, b ); - b = y.s; - - // Either NaN? - if ( !a || !b ) return new BigNumber(NaN); - - // Signs differ? - if ( a != b ) { - y.s = -b; - return x.plus(y); - } - - var xe = x.e / LOG_BASE, - ye = y.e / LOG_BASE, - xc = x.c, - yc = y.c; - - if ( !xe || !ye ) { - - // Either Infinity? - if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN ); - - // Either zero? - if ( !xc[0] || !yc[0] ) { - - // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. - return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x : - - // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity - ROUNDING_MODE == 3 ? -0 : 0 ); - } - } - - xe = bitFloor(xe); - ye = bitFloor(ye); - xc = xc.slice(); - - // Determine which is the bigger number. - if ( a = xe - ye ) { - - if ( xLTy = a < 0 ) { - a = -a; - t = xc; - } else { - ye = xe; - t = yc; - } - - t.reverse(); - - // Prepend zeros to equalise exponents. - for ( b = a; b--; t.push(0) ); - t.reverse(); - } else { - - // Exponents equal. Check digit by digit. - j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b; - - for ( a = b = 0; b < j; b++ ) { - - if ( xc[b] != yc[b] ) { - xLTy = xc[b] < yc[b]; - break; - } - } - } - - // x < y? Point xc to the array of the bigger number. - if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s; - - b = ( j = yc.length ) - ( i = xc.length ); - - // Append zeros to xc if shorter. - // No need to add zeros to yc if shorter as subtract only needs to start at yc.length. - if ( b > 0 ) for ( ; b--; xc[i++] = 0 ); - b = BASE - 1; - - // Subtract yc from xc. - for ( ; j > a; ) { - - if ( xc[--j] < yc[j] ) { - for ( i = j; i && !xc[--i]; xc[i] = b ); - --xc[i]; - xc[j] += BASE; - } - - xc[j] -= yc[j]; - } - - // Remove leading zeros and adjust exponent accordingly. - for ( ; xc[0] == 0; xc.splice(0, 1), --ye ); - - // Zero? - if ( !xc[0] ) { - - // Following IEEE 754 (2008) 6.3, - // n - n = +0 but n - n = -0 when rounding towards -Infinity. - y.s = ROUNDING_MODE == 3 ? -1 : 1; - y.c = [ y.e = 0 ]; - return y; - } - - // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity - // for finite x and y. - return normalise( y, xc, ye ); - }; - - - /* - * n % 0 = N - * n % N = N - * n % I = n - * 0 % n = 0 - * -0 % n = -0 - * 0 % 0 = N - * 0 % N = N - * 0 % I = 0 - * N % n = N - * N % 0 = N - * N % N = N - * N % I = N - * I % n = N - * I % 0 = N - * I % N = N - * I % I = N - * - * Return a new BigNumber whose value is the value of this BigNumber modulo the value of - * BigNumber(y, b). The result depends on the value of MODULO_MODE. - */ - P.modulo = P.mod = function ( y, b ) { - var q, s, - x = this; - - y = new BigNumber( y, b ); - - // Return NaN if x is Infinity or NaN, or y is NaN or zero. - if ( !x.c || !y.s || y.c && !y.c[0] ) { - return new BigNumber(NaN); - - // Return x if y is Infinity or x is zero. - } else if ( !y.c || x.c && !x.c[0] ) { - return new BigNumber(x); - } - - if ( MODULO_MODE == 9 ) { - - // Euclidian division: q = sign(y) * floor(x / abs(y)) - // r = x - qy where 0 <= r < abs(y) - s = y.s; - y.s = 1; - q = div( x, y, 0, 3 ); - y.s = s; - q.s *= s; - } else { - q = div( x, y, 0, MODULO_MODE ); - } - - return x.minus( q.times(y) ); - }; - - - /* - * n * 0 = 0 - * n * N = N - * n * I = I - * 0 * n = 0 - * 0 * 0 = 0 - * 0 * N = N - * 0 * I = N - * N * n = N - * N * 0 = N - * N * N = N - * N * I = N - * I * n = I - * I * 0 = N - * I * N = N - * I * I = I - * - * Return a new BigNumber whose value is the value of this BigNumber multiplied by the value - * of BigNumber(y, b). - */ - P.multipliedBy = P.times = function ( y, b ) { - var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc, - base, sqrtBase, - x = this, - xc = x.c, - yc = ( y = new BigNumber( y, b ) ).c; - - // Either NaN, ±Infinity or ±0? - if ( !xc || !yc || !xc[0] || !yc[0] ) { - - // Return NaN if either is NaN, or one is 0 and the other is Infinity. - if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) { - y.c = y.e = y.s = null; - } else { - y.s *= x.s; - - // Return ±Infinity if either is ±Infinity. - if ( !xc || !yc ) { - y.c = y.e = null; - - // Return ±0 if either is ±0. - } else { - y.c = [0]; - y.e = 0; - } - } - - return y; - } - - e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE ); - y.s *= x.s; - xcL = xc.length; - ycL = yc.length; - - // Ensure xc points to longer array and xcL to its length. - if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i; - - // Initialise the result array with zeros. - for ( i = xcL + ycL, zc = []; i--; zc.push(0) ); - - base = BASE; - sqrtBase = SQRT_BASE; - - for ( i = ycL; --i >= 0; ) { - c = 0; - ylo = yc[i] % sqrtBase; - yhi = yc[i] / sqrtBase | 0; - - for ( k = xcL, j = i + k; j > i; ) { - xlo = xc[--k] % sqrtBase; - xhi = xc[k] / sqrtBase | 0; - m = yhi * xlo + xhi * ylo; - xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c; - c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi; - zc[j--] = xlo % base; - } - - zc[j] = c; - } - - if (c) { - ++e; - } else { - zc.splice(0, 1); - } - - return normalise( y, zc, e ); - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber negated, - * i.e. multiplied by -1. - */ - P.negated = function () { - var x = new BigNumber(this); - x.s = -x.s || null; - return x; - }; - - - /* - * n + 0 = n - * n + N = N - * n + I = I - * 0 + n = n - * 0 + 0 = 0 - * 0 + N = N - * 0 + I = I - * N + n = N - * N + 0 = N - * N + N = N - * N + I = N - * I + n = I - * I + 0 = I - * I + N = N - * I + I = I - * - * Return a new BigNumber whose value is the value of this BigNumber plus the value of - * BigNumber(y, b). - */ - P.plus = function ( y, b ) { - var t, - x = this, - a = x.s; - - y = new BigNumber( y, b ); - b = y.s; - - // Either NaN? - if ( !a || !b ) return new BigNumber(NaN); - - // Signs differ? - if ( a != b ) { - y.s = -b; - return x.minus(y); - } - - var xe = x.e / LOG_BASE, - ye = y.e / LOG_BASE, - xc = x.c, - yc = y.c; - - if ( !xe || !ye ) { - - // Return ±Infinity if either ±Infinity. - if ( !xc || !yc ) return new BigNumber( a / 0 ); - - // Either zero? - // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. - if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 ); - } - - xe = bitFloor(xe); - ye = bitFloor(ye); - xc = xc.slice(); - - // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts. - if ( a = xe - ye ) { - if ( a > 0 ) { - ye = xe; - t = yc; - } else { - a = -a; - t = xc; - } - - t.reverse(); - for ( ; a--; t.push(0) ); - t.reverse(); - } - - a = xc.length; - b = yc.length; - - // Point xc to the longer array, and b to the shorter length. - if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a; - - // Only start adding at yc.length - 1 as the further digits of xc can be ignored. - for ( a = 0; b; ) { - a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0; - xc[b] = BASE === xc[b] ? 0 : xc[b] % BASE; - } - - if (a) { - xc = [a].concat(xc); - ++ye; - } - - // No need to check for zero, as +x + +y != 0 && -x + -y != 0 - // ye = MAX_EXP + 1 possible - return normalise( y, xc, ye ); - }; - - - /* - * If sd is undefined or null or true or false, return the number of significant digits of - * the value of this BigNumber, or null if the value of this BigNumber is ±Infinity or NaN. - * If sd is true include integer-part trailing zeros in the count. - * - * Otherwise, if sd is a number, return a new BigNumber whose value is the value of this - * BigNumber rounded to a maximum of sd significant digits using rounding mode rm, or - * ROUNDING_MODE if rm is omitted. - * - * sd {number|boolean} number: significant digits: integer, 1 to MAX inclusive. - * boolean: whether to count integer-part trailing zeros: true or false. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {sd|rm}' - */ - P.precision = P.sd = function ( sd, rm ) { - var c, n, v, - x = this; - - if ( sd != null && sd !== !!sd ) { - intCheck( sd, 1, MAX ); - if ( rm == null ) rm = ROUNDING_MODE; - else intCheck( rm, 0, 8 ); - - return round( new BigNumber(x), sd, rm ); - } - - if ( !( c = x.c ) ) return null; - v = c.length - 1; - n = v * LOG_BASE + 1; - - if ( v = c[v] ) { - - // Subtract the number of trailing zeros of the last element. - for ( ; v % 10 == 0; v /= 10, n-- ); - - // Add the number of digits of the first element. - for ( v = c[0]; v >= 10; v /= 10, n++ ); - } - - if ( sd && x.e + 1 > n ) n = x.e + 1; - - return n; - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber shifted by k places - * (powers of 10). Shift to the right if n > 0, and to the left if n < 0. - * - * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {k}' - */ - P.shiftedBy = function (k) { - intCheck( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER ); - return this.times( '1e' + k ); - }; - - - /* - * sqrt(-n) = N - * sqrt( N) = N - * sqrt(-I) = N - * sqrt( I) = I - * sqrt( 0) = 0 - * sqrt(-0) = -0 - * - * Return a new BigNumber whose value is the square root of the value of this BigNumber, - * rounded according to DECIMAL_PLACES and ROUNDING_MODE. - */ - P.squareRoot = P.sqrt = function () { - var m, n, r, rep, t, - x = this, - c = x.c, - s = x.s, - e = x.e, - dp = DECIMAL_PLACES + 4, - half = new BigNumber('0.5'); - - // Negative/NaN/Infinity/zero? - if ( s !== 1 || !c || !c[0] ) { - return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 ); - } - - // Initial estimate. - s = Math.sqrt( +x ); - - // Math.sqrt underflow/overflow? - // Pass x to Math.sqrt as integer, then adjust the exponent of the result. - if ( s == 0 || s == 1 / 0 ) { - n = coeffToString(c); - if ( ( n.length + e ) % 2 == 0 ) n += '0'; - s = Math.sqrt(n); - e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 ); - - if ( s == 1 / 0 ) { - n = '1e' + e; - } else { - n = s.toExponential(); - n = n.slice( 0, n.indexOf('e') + 1 ) + e; - } - - r = new BigNumber(n); - } else { - r = new BigNumber( s + '' ); - } - - // Check for zero. - // r could be zero if MIN_EXP is changed after the this value was created. - // This would cause a division by zero (x/t) and hence Infinity below, which would cause - // coeffToString to throw. - if ( r.c[0] ) { - e = r.e; - s = e + dp; - if ( s < 3 ) s = 0; - - // Newton-Raphson iteration. - for ( ; ; ) { - t = r; - r = half.times( t.plus( div( x, t, dp, 1 ) ) ); - - if ( coeffToString( t.c ).slice( 0, s ) === ( n = - coeffToString( r.c ) ).slice( 0, s ) ) { - - // The exponent of r may here be one less than the final result exponent, - // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits - // are indexed correctly. - if ( r.e < e ) --s; - n = n.slice( s - 3, s + 1 ); - - // The 4th rounding digit may be in error by -1 so if the 4 rounding digits - // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the - // iteration. - if ( n == '9999' || !rep && n == '4999' ) { - - // On the first iteration only, check to see if rounding up gives the - // exact result as the nines may infinitely repeat. - if ( !rep ) { - round( t, t.e + DECIMAL_PLACES + 2, 0 ); - - if ( t.times(t).eq(x) ) { - r = t; - break; - } - } - - dp += 4; - s += 4; - rep = 1; - } else { - - // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact - // result. If not, then there are further digits and m will be truthy. - if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) { - - // Truncate to the first rounding digit. - round( r, r.e + DECIMAL_PLACES + 2, 1 ); - m = !r.times(r).eq(x); - } - - break; - } - } - } - } - - return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m ); - }; - - - /* - * Return a string representing the value of this BigNumber in exponential notation and - * rounded using ROUNDING_MODE to dp fixed decimal places. - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' - */ - P.toExponential = function ( dp, rm ) { - if ( dp != null ) { - intCheck( dp, 0, MAX ); - dp++; - } - return format( this, dp, rm, 1 ); - }; - - - /* - * Return a string representing the value of this BigNumber in fixed-point notation rounding - * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted. - * - * Note: as with JavaScript's number type, (-0).toFixed(0) is '0', - * but e.g. (-0.00001).toFixed(0) is '-0'. - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' - */ - P.toFixed = function ( dp, rm ) { - if ( dp != null ) { - intCheck( dp, 0, MAX ); - dp = dp + this.e + 1; - } - return format( this, dp, rm ); - }; - - - /* - * Return a string representing the value of this BigNumber in fixed-point notation rounded - * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties - * of the FORMAT object (see BigNumber.set). - * - * FORMAT = { - * decimalSeparator : '.', - * groupSeparator : ',', - * groupSize : 3, - * secondaryGroupSize : 0, - * fractionGroupSeparator : '\xA0', // non-breaking space - * fractionGroupSize : 0 - * }; - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp|rm}' - */ - P.toFormat = function ( dp, rm ) { - var str = this.toFixed( dp, rm ); - - if ( this.c ) { - var i, - arr = str.split('.'), - g1 = +FORMAT.groupSize, - g2 = +FORMAT.secondaryGroupSize, - groupSeparator = FORMAT.groupSeparator, - intPart = arr[0], - fractionPart = arr[1], - isNeg = this.s < 0, - intDigits = isNeg ? intPart.slice(1) : intPart, - len = intDigits.length; - - if (g2) i = g1, g1 = g2, g2 = i, len -= i; - - if ( g1 > 0 && len > 0 ) { - i = len % g1 || g1; - intPart = intDigits.substr( 0, i ); - - for ( ; i < len; i += g1 ) { - intPart += groupSeparator + intDigits.substr( i, g1 ); - } - - if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i); - if (isNeg) intPart = '-' + intPart; - } - - str = fractionPart - ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize ) - ? fractionPart.replace( new RegExp( '\\d{' + g2 + '}\\B', 'g' ), - '$&' + FORMAT.fractionGroupSeparator ) - : fractionPart ) - : intPart; - } - - return str; - }; - - - /* - * Return a string array representing the value of this BigNumber as a simple fraction with - * an integer numerator and an integer denominator. The denominator will be a positive - * non-zero value less than or equal to the specified maximum denominator. If a maximum - * denominator is not specified, the denominator will be the lowest value necessary to - * represent the number exactly. - * - * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator. - * - * '[BigNumber Error] Argument {not an integer|out of range} : {md}' - */ - P.toFraction = function (md) { - var arr, d, d0, d1, d2, e, exp, n, n0, n1, q, s, - x = this, - xc = x.c; - - if ( md != null ) { - n = new BigNumber(md); - - if ( !n.isInteger() || n.lt(ONE) ) { - throw Error - ( bignumberError + 'Argument ' + - ( n.isInteger() ? 'out of range: ' : 'not an integer: ' ) + md ); - } - } - - if ( !xc ) return x.toString(); - - d = new BigNumber(ONE); - n1 = d0 = new BigNumber(ONE); - d1 = n0 = new BigNumber(ONE); - s = coeffToString(xc); - - // Determine initial denominator. - // d is a power of 10 and the minimum max denominator that specifies the value exactly. - e = d.e = s.length - x.e - 1; - d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ]; - md = !md || n.comparedTo(d) > 0 ? ( e > 0 ? d : n1 ) : n; - - exp = MAX_EXP; - MAX_EXP = 1 / 0; - n = new BigNumber(s); - - // n0 = d1 = 0 - n0.c[0] = 0; - - for ( ; ; ) { - q = div( n, d, 0, 1 ); - d2 = d0.plus( q.times(d1) ); - if ( d2.comparedTo(md) == 1 ) break; - d0 = d1; - d1 = d2; - n1 = n0.plus( q.times( d2 = n1 ) ); - n0 = d2; - d = n.minus( q.times( d2 = d ) ); - n = d2; - } - - d2 = div( md.minus(d0), d1, 0, 1 ); - n0 = n0.plus( d2.times(n1) ); - d0 = d0.plus( d2.times(d1) ); - n0.s = n1.s = x.s; - e *= 2; - - // Determine which fraction is closer to x, n0/d0 or n1/d1 - arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().comparedTo( - div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1 - ? [ n1.toString(), d1.toString() ] - : [ n0.toString(), d0.toString() ]; - - MAX_EXP = exp; - return arr; - }; - - - /* - * Return the value of this BigNumber converted to a number primitive. - */ - P.toNumber = function () { - return +this; - }; - - - /* - * Return a BigNumber whose value is the value of this BigNumber exponentiated by n. - * - * If m is present, return the result modulo m. - * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE. - * If POW_PRECISION is non-zero and m is not present, round to POW_PRECISION using ROUNDING_MODE. - * - * The modular power operation works efficiently when x, n, and m are positive integers, - * otherwise it is equivalent to calculating x.exponentiatedBy(n).modulo(m) with a POW_PRECISION of 0. - * - * n {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. - * [m] {number|string|BigNumber} The modulus. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {n}' - * - * Performs 54 loop iterations for n of 9007199254740991. - */ - P.exponentiatedBy = P.pow = function ( n, m ) { - var i, k, y, z, - x = this; - - intCheck( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER ); - if ( m != null ) m = new BigNumber(m); - - if (m) { - if ( n > 1 && x.gt(ONE) && x.isInteger() && m.gt(ONE) && m.isInteger() ) { - x = x.mod(m); - } else { - z = m; - - // Nullify m so only a single mod operation is performed at the end. - m = null; - } - } else if (POW_PRECISION) { - - // Truncating each coefficient array to a length of k after each multiplication - // equates to truncating significant digits to POW_PRECISION + [28, 41], - // i.e. there will be a minimum of 28 guard digits retained. - //k = mathceil( POW_PRECISION / LOG_BASE + 1.5 ); // gives [9, 21] guard digits. - k = mathceil( POW_PRECISION / LOG_BASE + 2 ); - } - - y = new BigNumber(ONE); - - for ( i = mathfloor( n < 0 ? -n : n ); ; ) { - if ( i % 2 ) { - y = y.times(x); - if ( !y.c ) break; - if (k) { - if ( y.c.length > k ) y.c.length = k; - } else if (m) { - y = y.mod(m); - } - } - - i = mathfloor( i / 2 ); - if ( !i ) break; - x = x.times(x); - if (k) { - if ( x.c && x.c.length > k ) x.c.length = k; - } else if (m) { - x = x.mod(m); - } - } - - if (m) return y; - if ( n < 0 ) y = ONE.div(y); - - return z ? y.mod(z) : k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y; - }; - - - /* - * Return a string representing the value of this BigNumber rounded to sd significant digits - * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits - * necessary to represent the integer part of the value in fixed-point notation, then use - * exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {sd|rm}' - */ - P.toPrecision = function ( sd, rm ) { - if ( sd != null ) intCheck( sd, 1, MAX ); - return format( this, sd, rm, 2 ); - }; - - - /* - * Return a string representing the value of this BigNumber in base b, or base 10 if b is - * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and - * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent - * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than - * TO_EXP_NEG, return exponential notation. - * - * [b] {number} Integer, 2 to ALPHABET.length inclusive. - * - * '[BigNumber Error] Base {not a primitive number|not an integer|out of range}: {b}' - */ - P.toString = function (b) { - var str, - n = this, - s = n.s, - e = n.e; - - // Infinity or NaN? - if ( e === null ) { - - if (s) { - str = 'Infinity'; - if ( s < 0 ) str = '-' + str; - } else { - str = 'NaN'; - } - } else { - str = coeffToString( n.c ); - - if ( b == null ) { - str = e <= TO_EXP_NEG || e >= TO_EXP_POS - ? toExponential( str, e ) - : toFixedPoint( str, e, '0' ); - } else { - intCheck( b, 2, ALPHABET.length, 'Base' ); - str = convertBase( toFixedPoint( str, e, '0' ), 10, b, s, true ); - } - - if ( s < 0 && n.c[0] ) str = '-' + str; - } - - return str; - }; - - - /* - * Return as toString, but do not accept a base argument, and include the minus sign for - * negative zero. - */ - P.valueOf = P.toJSON = function () { - var str, - n = this, - e = n.e; - - if ( e === null ) return n.toString(); - - str = coeffToString( n.c ); - - str = e <= TO_EXP_NEG || e >= TO_EXP_POS - ? toExponential( str, e ) - : toFixedPoint( str, e, '0' ); - - return n.s < 0 ? '-' + str : str; - }; - - - P._isBigNumber = true; - - if ( configObject != null ) BigNumber.set(configObject); - - return BigNumber; -} - - -// PRIVATE HELPER FUNCTIONS - - -function bitFloor(n) { - var i = n | 0; - return n > 0 || n === i ? i : i - 1; -} - - -// Return a coefficient array as a string of base 10 digits. -function coeffToString(a) { - var s, z, - i = 1, - j = a.length, - r = a[0] + ''; - - for ( ; i < j; ) { - s = a[i++] + ''; - z = LOG_BASE - s.length; - for ( ; z--; s = '0' + s ); - r += s; - } - - // Determine trailing zeros. - for ( j = r.length; r.charCodeAt(--j) === 48; ); - return r.slice( 0, j + 1 || 1 ); -} - - -// Compare the value of BigNumbers x and y. -function compare( x, y ) { - var a, b, - xc = x.c, - yc = y.c, - i = x.s, - j = y.s, - k = x.e, - l = y.e; - - // Either NaN? - if ( !i || !j ) return null; - - a = xc && !xc[0]; - b = yc && !yc[0]; - - // Either zero? - if ( a || b ) return a ? b ? 0 : -j : i; - - // Signs differ? - if ( i != j ) return i; - - a = i < 0; - b = k == l; - - // Either Infinity? - if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1; - - // Compare exponents. - if ( !b ) return k > l ^ a ? 1 : -1; - - j = ( k = xc.length ) < ( l = yc.length ) ? k : l; - - // Compare digit by digit. - for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1; - - // Compare lengths. - return k == l ? 0 : k > l ^ a ? 1 : -1; -} - - -/* - * Check that n is a primitive number, an integer, and in range, otherwise throw. - */ -function intCheck( n, min, max, name ) { - if ( n < min || n > max || n !== ( n < 0 ? mathceil(n) : mathfloor(n) ) ) { - throw Error - ( bignumberError + ( name || 'Argument' ) + ( typeof n == 'number' - ? n < min || n > max ? ' out of range: ' : ' not an integer: ' - : ' not a primitive number: ' ) + n ); - } -} - - -function isArray(obj) { - return Object.prototype.toString.call(obj) == '[object Array]'; -} - - -function toExponential( str, e ) { - return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) + - ( e < 0 ? 'e' : 'e+' ) + e; -} - - -function toFixedPoint( str, e, z ) { - var len, zs; - - // Negative exponent? - if ( e < 0 ) { - - // Prepend zeros. - for ( zs = z + '.'; ++e; zs += z ); - str = zs + str; - - // Positive exponent - } else { - len = str.length; - - // Append zeros. - if ( ++e > len ) { - for ( zs = z, e -= len; --e; zs += z ); - str += zs; - } else if ( e < len ) { - str = str.slice( 0, e ) + '.' + str.slice(e); - } - } - - return str; -} - - -// EXPORT - - -BigNumber = clone(); -BigNumber['default'] = BigNumber.BigNumber = BigNumber; - -export default BigNumber; \ No newline at end of file diff --git a/packages/instant/test/util/maybe_big_number.test.ts b/packages/instant/test/util/maybe_big_number.test.ts index f32e33eb14..508e8aaf06 100644 --- a/packages/instant/test/util/maybe_big_number.test.ts +++ b/packages/instant/test/util/maybe_big_number.test.ts @@ -2,12 +2,9 @@ import { BigNumber } from '@0x/utils'; import { maybeBigNumberUtil } from '../../src/util/maybe_big_number'; -// import PrevBigNumber from './dependencies/prevbignumber'; - const BIG_NUMBER_1 = new BigNumber('10.1'); const BIG_NUMBER_2 = new BigNumber('10.1'); const BIG_NUMBER_3 = new BigNumber('11.1'); -// const PREVBIG_NUMBER_1 = new PrevBigNumber('11.1'); describe('maybeBigNumberUtil', () => { describe('stringToMaybeBigNumber', () => { @@ -40,32 +37,29 @@ describe('maybeBigNumberUtil', () => { }); }); - // describe('bigNumberOrStringToMaybeBigNumber', () => { - // it('should return BigNumber (>=v8.0.0) constructed with value if type is string', () => { - // const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('10.1'); - // if (!!bn) { - // expect(bn.toString()).toEqual('10.1'); - // } - // }); - // it('should return undefined if value is NaN', () => { - // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('NaN')).toEqual(undefined); - // }); - // it('should return undefined if value as string is not valid (i.e not numeric)', () => { - // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('test')).toEqual(undefined); - // }); - // it('should return undefined if value as string is not valid (i.e not numeric)', () => { - // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('test')).toEqual(undefined); - // }); - // it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber ( { - // const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(PREVBIG_NUMBER_1); - // expect(BigNumber.isBigNumber(bn)).toEqual(true); - // }); - // it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber (>=v8.0.0)', () => { - // const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(BIG_NUMBER_1); - // expect(BigNumber.isBigNumber(bn)).toEqual(true); - // }); - // it('should return undefined if value is not BigNumber or string', () => { - // expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(true)).toEqual(undefined); - // }); - // }); + // this doesn't test coercing a pre v8.0.0 version of big number to desired version + describe('toMaybeBigNumber', () => { + it('should return BigNumber (>=v8.0.0) constructed with value if type is string', () => { + const bn = maybeBigNumberUtil.toMaybeBigNumber('10.1'); + if (!!bn) { + expect(bn.toString()).toEqual('10.1'); + } + }); + it('should return undefined if value is NaN', () => { + expect(maybeBigNumberUtil.toMaybeBigNumber('NaN')).toEqual(undefined); + }); + it('should return undefined if value as string is not valid (i.e not numeric)', () => { + expect(maybeBigNumberUtil.toMaybeBigNumber('test')).toEqual(undefined); + }); + it('should return undefined if value as string is not valid (i.e not numeric)', () => { + expect(maybeBigNumberUtil.toMaybeBigNumber('test')).toEqual(undefined); + }); + it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber (>=v8.0.0)', () => { + const bn = maybeBigNumberUtil.toMaybeBigNumber(BIG_NUMBER_1); + expect(BigNumber.isBigNumber(bn)).toEqual(true); + }); + it('should return undefined if value is not BigNumber or string', () => { + expect(maybeBigNumberUtil.toMaybeBigNumber(true)).toEqual(undefined); + }); + }); }); diff --git a/packages/instant/test/util/order_coercion.test.ts b/packages/instant/test/util/order_coercion.test.ts new file mode 100644 index 0000000000..f7a958c9d3 --- /dev/null +++ b/packages/instant/test/util/order_coercion.test.ts @@ -0,0 +1,103 @@ +import { BigNumber } from '@0x/utils'; + +import { orderCoercionUtil } from '../../src/util/order_coercion'; + +const ORDER = { + senderAddress: '0x0000000000000000000000000000000000000000', + makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e', + takerAddress: '0x0000000000000000000000000000000000000000', + makerFee: new BigNumber('0'), + takerFee: new BigNumber('0'), + makerAssetAmount: new BigNumber('200000000000000000000'), + takerAssetAmount: new BigNumber('10000000000000000000'), + makerAssetData: '0xf47261b00000000000000000000000008cb3971b8eb709c14616bd556ff6683019e90d9c', + takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c', + expirationTimeSeconds: new BigNumber('1601535600'), + feeRecipientAddress: '0x0000000000000000000000000000000000000000', + salt: new BigNumber('3101985707338942582579795423923841749956600670712030922928319824580764688653'), + signature: + '0x1bd4d5686fea801fe33c68c4944356085e7e6cb553eb7073160abd815609f714e85fb47f44b7ffd0a2a1321ac40d72d55163869d0a50fdb5a402132150fe33a08403', + exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2', +}; + +const STRING_ORDER = { + senderAddress: '0x0000000000000000000000000000000000000000', + makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e', + takerAddress: '0x0000000000000000000000000000000000000000', + makerFee: '0', + takerFee: '0', + makerAssetAmount: '300000000000000000000', + takerAssetAmount: '31000000000000000000', + makerAssetData: '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa', + takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c', + expirationTimeSeconds: '2524636800', + feeRecipientAddress: '0x0000000000000000000000000000000000000000', + salt: '64592004666704945574675477805199411288137454783320798602050822322450089238268', + signature: + '0x1c13cacddca8d7d8248e91f412377e68f8f1f9891a59a6c1b2eea9f7b33558c30c4fb86a448e08ab7def40a28fb3a3062dcb33bb3c45302447fce5c4288b7c7f5b03', + exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2', +}; + +const ORDERS = [ORDER, STRING_ORDER]; + +describe('orderCoercionUtil', () => { + describe('coerceFieldsToBigNumbers', () => { + it('should coerce all fields specified to a big number', () => { + const coercedOrder = orderCoercionUtil.coerceFieldsToBigNumbers(STRING_ORDER, ['makerFee', 'takerFee']); + expect(coercedOrder.makerFee.toString()).toEqual('0'); + expect(coercedOrder.takerFee.toString()).toEqual('0'); + }); + it("should throw if a field can't be found", () => { + expect(() => { + orderCoercionUtil.coerceFieldsToBigNumbers(ORDER, ['salty']); + }).toThrow("Could not find field 'salty' while converting fields to BigNumber."); + }); + it('should not change value if not numeric string or big number', () => { + const obj = { number: 'number' }; + const coercedObj = orderCoercionUtil.coerceFieldsToBigNumbers(obj, ['number']); + expect(coercedObj).toEqual({ + number: 'number', + }); + }); + }); + // Note: this doesn't test coercing pre v8.0.0 BigNumber versions to specified one used by 0x + describe('coerceOrderFieldsToBigNumber', () => { + it('should convert string values in order to big number', () => { + const coercedOrder = orderCoercionUtil.coerceOrderFieldsToBigNumber(STRING_ORDER); + expect(coercedOrder.makerFee.toString()).toEqual(STRING_ORDER.makerFee); + expect(coercedOrder.takerFee.toString()).toEqual(STRING_ORDER.takerFee); + expect(coercedOrder.takerAssetAmount.toString()).toEqual(STRING_ORDER.takerAssetAmount); + expect(coercedOrder.makerAssetAmount.toString()).toEqual(STRING_ORDER.makerAssetAmount); + expect(coercedOrder.salt.toString()).toEqual(STRING_ORDER.salt); + expect(coercedOrder.expirationTimeSeconds.toString()).toEqual(STRING_ORDER.expirationTimeSeconds); + }); + it('should convert big number values in order to big number', () => { + const coercedOrder = orderCoercionUtil.coerceOrderFieldsToBigNumber(ORDER); + expect(coercedOrder.makerFee).toEqual(ORDER.makerFee); + expect(coercedOrder.takerFee).toEqual(ORDER.takerFee); + expect(coercedOrder.takerAssetAmount).toEqual(ORDER.takerAssetAmount); + expect(coercedOrder.makerAssetAmount).toEqual(ORDER.makerAssetAmount); + expect(coercedOrder.salt).toEqual(ORDER.salt); + expect(coercedOrder.expirationTimeSeconds).toEqual(ORDER.expirationTimeSeconds); + }); + }); + // Note: this doesn't test coercing pre v8.0.0 BigNumber versions to specified one used by 0x + describe('coerceOrderArrayFieldsToBigNumber', () => { + it('should convert string values and big numbers in orders to big number', () => { + const coercedOrders = orderCoercionUtil.coerceOrderArrayFieldsToBigNumber(ORDERS); + expect(coercedOrders[0].makerFee).toEqual(ORDER.makerFee); + expect(coercedOrders[0].takerFee).toEqual(ORDER.takerFee); + expect(coercedOrders[0].takerAssetAmount).toEqual(ORDER.takerAssetAmount); + expect(coercedOrders[0].makerAssetAmount).toEqual(ORDER.makerAssetAmount); + expect(coercedOrders[0].salt).toEqual(ORDER.salt); + expect(coercedOrders[0].expirationTimeSeconds).toEqual(ORDER.expirationTimeSeconds); + + expect(coercedOrders[1].makerFee.toString()).toEqual(STRING_ORDER.makerFee); + expect(coercedOrders[1].takerFee.toString()).toEqual(STRING_ORDER.takerFee); + expect(coercedOrders[1].takerAssetAmount.toString()).toEqual(STRING_ORDER.takerAssetAmount); + expect(coercedOrders[1].makerAssetAmount.toString()).toEqual(STRING_ORDER.makerAssetAmount); + expect(coercedOrders[1].salt.toString()).toEqual(STRING_ORDER.salt); + expect(coercedOrders[1].expirationTimeSeconds.toString()).toEqual(STRING_ORDER.expirationTimeSeconds); + }); + }); +}); From 4079563f5dca96477bb13935c1cc30ad8224ae4c Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 11:56:49 -0800 Subject: [PATCH 06/39] More robust/simple signature parsing, using a parse tree --- .../src/abi_encoder/evm_data_type_factory.ts | 87 ++++++++-- .../src/abi_encoder/evm_data_types/method.ts | 5 + packages/utils/src/abi_encoder/index.ts | 1 + .../src/abi_encoder/utils/signature_parser.ts | 159 ++++++++---------- 4 files changed, 150 insertions(+), 102 deletions(-) diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts index 2686491487..613eb887f1 100644 --- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts +++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts @@ -2,7 +2,7 @@ import { DataItem, MethodAbi } from 'ethereum-types'; import * as _ from 'lodash'; -import { generateDataItemsFromSignature } from './utils/signature_parser'; +import { generateDataItemFromSignature } from './utils/signature_parser'; import { DataType } from './abstract_data_types/data_type'; import { DataTypeFactory } from './abstract_data_types/interfaces'; @@ -134,32 +134,87 @@ export class EvmDataTypeFactory implements DataTypeFactory { /** * Convenience function for creating a DataType from different inputs. - * @param input A single or set of DataItem or a DataType signature. - * A signature in the form of '' is interpreted as a `DataItem` - * For example, 'string' is interpreted as {type: 'string'} - * A signature in the form '(, , ..., )' is interpreted as `DataItem[]` - * For eaxmple, '(string, uint256)' is interpreted as [{type: 'string'}, {type: 'uint256'}] + * @param input A single or set of DataItem or a signature for an EVM data type. * @return DataType corresponding to input. */ export function create(input: DataItem | DataItem[] | string): DataType { - // Handle different types of input - const isSignature = typeof input === 'string'; - const isTupleSignature = isSignature && (input as string).startsWith('('); - const shouldParseAsTuple = isTupleSignature || _.isArray(input); - // Create input `dataItem` + const dataItem = consolidateDataItemsIntoSingle(input); + const dataType = EvmDataTypeFactory.getInstance().create(dataItem); + return dataType; +} + +/** + * Convenience function to aggregate a single input or a set of inputs into a single DataItem. + * An array of data items is grouped into a single tuple. + * @param input A single data item; a set of data items; a signature. + * @return A single data item corresponding to input. + */ +function consolidateDataItemsIntoSingle(input: DataItem | DataItem[] | string): DataItem { let dataItem: DataItem; - if (shouldParseAsTuple) { - const dataItems = isSignature ? generateDataItemsFromSignature(input as string) : (input as DataItem[]); + if (_.isArray(input)) { + const dataItems = input as DataItem[]; dataItem = { name: '', type: 'tuple', components: dataItems, }; } else { - dataItem = isSignature ? generateDataItemsFromSignature(input as string)[0] : (input as DataItem); + dataItem = typeof input === 'string' ? generateDataItemFromSignature(input) : (input as DataItem); } - // Create data type - const dataType = EvmDataTypeFactory.getInstance().create(dataItem); + return dataItem; +} + +/** + * Convenience function for creating a Method encoder from different inputs. + * @param methodName name of method. + * @param input A single data item; a set of data items; a signature; or an array of signatures (optional). + * @param output A single data item; a set of data items; a signature; or an array of signatures (optional). + * @return Method corresponding to input. + */ +export function createMethod( + methodName: string, + input?: DataItem | DataItem[] | string | string[], + output?: DataItem | DataItem[] | string | string[], +): Method { + const methodInput = _.isUndefined(input) ? [] : consolidateDataItemsIntoArray(input); + const methodOutput = _.isUndefined(output) ? [] : consolidateDataItemsIntoArray(output); + const methodAbi: MethodAbi = { + name: methodName, + inputs: methodInput, + outputs: methodOutput, + type: 'function', + // default fields not used by ABI + constant: false, + payable: false, + stateMutability: 'nonpayable', + }; + const dataType = new Method(methodAbi); return dataType; } + +/** + * Convenience function that aggregates a single input or a set of inputs into an array of DataItems. + * @param input A single data item; a set of data items; a signature; or an array of signatures. + * @return Array of data items corresponding to input. + */ +function consolidateDataItemsIntoArray(input: DataItem | DataItem[] | string | string[]): DataItem[] { + let dataItems: DataItem[]; + if (_.isArray(input) && _.isEmpty(input)) { + dataItems = []; + } else if (_.isArray(input) && typeof input[0] === 'string') { + dataItems = []; + _.each(input as string[], (signature: string) => { + const dataItem = generateDataItemFromSignature(signature); + dataItems.push(dataItem); + }); + } else if (_.isArray(input)) { + dataItems = input as DataItem[]; + } else if (typeof input === 'string') { + const dataItem = generateDataItemFromSignature(input); + dataItems = [dataItem]; + } else { + dataItems = [input as DataItem]; + } + return dataItems; +} /* tslint:enable no-construct */ diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts index c852a0fdfa..93746fa002 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/method.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts @@ -65,6 +65,11 @@ export class MethodDataType extends AbstractSetDataType { return this._methodSelector; } + public getReturnValueDataItem(): DataItem { + const returnValueDataItem = this._returnDataType.getDataItem(); + return returnValueDataItem; + } + private _computeSignature(): string { const memberSignature = this._computeSignatureOfMembers(); const methodSignature = `${this.getDataItem().name}${memberSignature}`; diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts index cfacfe075a..976bac8e6b 100644 --- a/packages/utils/src/abi_encoder/index.ts +++ b/packages/utils/src/abi_encoder/index.ts @@ -12,5 +12,6 @@ export { Tuple, UInt, create, + createMethod, } from './evm_data_type_factory'; export { DataType } from './abstract_data_types/data_type'; diff --git a/packages/utils/src/abi_encoder/utils/signature_parser.ts b/packages/utils/src/abi_encoder/utils/signature_parser.ts index 315784cead..d3996bf8e9 100644 --- a/packages/utils/src/abi_encoder/utils/signature_parser.ts +++ b/packages/utils/src/abi_encoder/utils/signature_parser.ts @@ -1,101 +1,88 @@ import { DataItem } from 'ethereum-types'; import * as _ from 'lodash'; -/** - * Returns an array of DataItem's corresponding to the input signature. - * A signature can be in two forms: '' or '(, , ...) - * An example of the first form would be 'address' or 'uint256' - * An example of the second form would be '(address, uint256)' - * Signatures can also include a name field, for example: 'foo address' or '(foo address, bar uint256)' - * @param signature of input DataItems - * @return DataItems derived from input signature - */ -export function generateDataItemsFromSignature(signature: string): DataItem[] { - let trimmedSignature = signature; - if (signature.startsWith('(')) { - if (!signature.endsWith(')')) { - throw new Error(`Failed to generate data item. Must end with ')'`); - } - trimmedSignature = signature.substr(1, signature.length - 2); +interface Node { + name: string; + value: string; + children: Node[]; + parent?: Node; +} + +function parseNode(node: Node): DataItem { + const components: DataItem[] = []; + _.each(node.children, (child: Node) => { + const component = parseNode(child); + components.push(component); + }); + const dataItem: DataItem = { + name: node.name, + type: node.value, + }; + if (!_.isEmpty(components)) { + dataItem.components = components; } - trimmedSignature += ','; - let isCurrTokenArray = false; - let currTokenArrayModifier = ''; - let isParsingArrayModifier = false; - let currToken = ''; - let parenCount = 0; - let currTokenName = ''; - const dataItems: DataItem[] = []; - for (const char of trimmedSignature) { - // Tokenize the type string while keeping track of parentheses. + return dataItem; +} + +/** + * Returns a DataItem corresponding to the input signature. + * A signature can be in two forms: `type` or `(type_1,type_2,...,type_n)` + * An example of the first form would be 'address' or 'uint256[]' or 'bytes[5][]' + * An example of the second form would be '(address,uint256)' or '(address,uint256)[]' + * @param signature of input DataItem. + * @return DataItem derived from input signature. + */ +export function generateDataItemFromSignature(signature: string): DataItem { + // No data item corresponds to an empty signature + if (_.isEmpty(signature)) { + throw new Error(`Cannot parse data item from empty signature, ''`); + } + // Create a parse tree for data item + let node: Node = { + name: '', + value: '', + children: [], + }; + for (const char of signature) { switch (char) { case '(': - parenCount += 1; - currToken += char; + const child = { + name: '', + value: '', + children: [], + parent: node, + }; + node.value = 'tuple'; + node.children.push(child); + node = child; break; + case ')': - parenCount -= 1; - currToken += char; - break; - case '[': - if (parenCount === 0) { - isParsingArrayModifier = true; - isCurrTokenArray = true; - currTokenArrayModifier += '['; - } else { - currToken += char; - } - break; - case ']': - if (parenCount === 0) { - isParsingArrayModifier = false; - currTokenArrayModifier += ']'; - } else { - currToken += char; - } - break; - case ' ': - if (parenCount === 0) { - currTokenName = currToken; - currToken = ''; - } else { - currToken += char; - } + node = node.parent as Node; break; + case ',': - if (parenCount === 0) { - // Generate new DataItem from token - const components = currToken.startsWith('(') ? generateDataItemsFromSignature(currToken) : []; - const isTuple = !_.isEmpty(components); - const dataItem: DataItem = { name: currTokenName, type: '' }; - if (isTuple) { - dataItem.type = 'tuple'; - dataItem.components = components; - } else { - dataItem.type = currToken; - } - if (isCurrTokenArray) { - dataItem.type += currTokenArrayModifier; - } - dataItems.push(dataItem); - // reset token state - currTokenName = ''; - currToken = ''; - isCurrTokenArray = false; - currTokenArrayModifier = ''; - break; - } else { - currToken += char; - break; - } + const sibling = { + name: '', + value: '', + children: [], + parent: node.parent, + }; + (node.parent as Node).children.push(sibling); + node = sibling; + break; + + case ' ': + node.name = node.value; + node.value = ''; + break; + default: - if (isParsingArrayModifier) { - currTokenArrayModifier += char; - } else { - currToken += char; - } + node.value += char; break; } } - return dataItems; + // Interpret data item from parse tree + const dataItem = parseNode(node); + return dataItem; } From eb5f7e36e9a83f7222b1a98d23c720a7573e7dbf Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 11:56:58 -0800 Subject: [PATCH 07/39] Signature parsing tests --- .../test/abi_encoder/evm_data_types_test.ts | 2 +- .../utils/test/abi_encoder/signature_test.ts | 393 ++++++++++++++++++ .../utils/test/abi_encoder/signature_tests.ts | 0 3 files changed, 394 insertions(+), 1 deletion(-) create mode 100644 packages/utils/test/abi_encoder/signature_test.ts delete mode 100644 packages/utils/test/abi_encoder/signature_tests.ts diff --git a/packages/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts index c09c0d9294..c802902072 100644 --- a/packages/utils/test/abi_encoder/evm_data_types_test.ts +++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts @@ -28,7 +28,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => { const decodedArgs = dataType.decode(encodedArgs); expect(decodedArgs).to.be.deep.equal(args); // Validate signature - const dataTypeFromSignature = AbiEncoder.create(dataType.getSignature(true)); + const dataTypeFromSignature = AbiEncoder.create(dataType.getSignature(false)); const argsEncodedFromSignature = dataTypeFromSignature.encode(args); expect(argsEncodedFromSignature).to.be.deep.equal(expectedEncodedArgs); }); diff --git a/packages/utils/test/abi_encoder/signature_test.ts b/packages/utils/test/abi_encoder/signature_test.ts new file mode 100644 index 0000000000..cee6fa5e57 --- /dev/null +++ b/packages/utils/test/abi_encoder/signature_test.ts @@ -0,0 +1,393 @@ +import * as chai from 'chai'; +import 'mocha'; + +import { AbiEncoder } from '../../src'; +import { chaiSetup } from '../utils/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe('ABI Encoder: Signatures', () => { + describe('Single type', () => { + it('Elementary', async () => { + const signature = 'uint256'; + const dataType = AbiEncoder.create(signature); + const dataTypeId = dataType.getDataItem().type; + expect(dataTypeId).to.be.equal('uint256'); + expect(dataType.getSignature()).to.be.equal(signature); + }); + it('Array', async () => { + const signature = 'string[]'; + const dataType = AbiEncoder.create(signature); + const dataItem = dataType.getDataItem(); + const expectedDataItem = { + name: '', + type: 'string[]', + }; + expect(dataItem).to.be.deep.equal(expectedDataItem); + expect(dataType.getSignature()).to.be.equal(signature); + }); + it('Multidimensional Array', async () => { + // Decode return value + const signature = 'uint256[4][][5]'; + const dataType = AbiEncoder.create(signature); + const dataTypeId = dataType.getDataItem().type; + expect(dataTypeId).to.be.equal(signature); + expect(dataType.getSignature()).to.be.equal(signature); + }); + it('Tuple with single element', async () => { + const signature = '(uint256)'; + const dataType = AbiEncoder.create(signature); + const dataItem = dataType.getDataItem(); + const expectedDataItem = { + name: '', + type: 'tuple', + components: [ + { + name: '', + type: 'uint256', + }, + ], + }; + expect(dataItem).to.be.deep.equal(expectedDataItem); + expect(dataType.getSignature()).to.be.equal(signature); + }); + it('Tuple with multiple elements', async () => { + const signature = '(uint256,string,bytes4)'; + const dataType = AbiEncoder.create(signature); + const dataItem = dataType.getDataItem(); + const expectedDataItem = { + name: '', + type: 'tuple', + components: [ + { + name: '', + type: 'uint256', + }, + { + name: '', + type: 'string', + }, + { + name: '', + type: 'bytes4', + }, + ], + }; + expect(dataItem).to.be.deep.equal(expectedDataItem); + expect(dataType.getSignature()).to.be.equal(signature); + }); + it('Tuple with nested array and nested tuple', async () => { + const signature = '(uint256[],(bytes),string[4],bytes4)'; + const dataType = AbiEncoder.create(signature); + const dataItem = dataType.getDataItem(); + const expectedDataItem = { + name: '', + type: 'tuple', + components: [ + { + name: '', + type: 'uint256[]', + }, + { + name: '', + type: 'tuple', + components: [ + { + name: '', + type: 'bytes', + }, + ], + }, + { + name: '', + type: 'string[4]', + }, + { + name: '', + type: 'bytes4', + }, + ], + }; + expect(dataItem).to.be.deep.equal(expectedDataItem); + expect(dataType.getSignature()).to.be.equal(signature); + }); + it('Array of complex tuples', async () => { + const signature = '(uint256[],(bytes),string[4],bytes4)[5][4][]'; + const dataType = AbiEncoder.create(signature); + const dataItem = dataType.getDataItem(); + const expectedDataItem = { + name: '', + type: 'tuple[5][4][]', + components: [ + { + name: '', + type: 'uint256[]', + }, + { + name: '', + type: 'tuple', + components: [ + { + name: '', + type: 'bytes', + }, + ], + }, + { + name: '', + type: 'string[4]', + }, + { + name: '', + type: 'bytes4', + }, + ], + }; + expect(dataItem).to.be.deep.equal(expectedDataItem); + expect(dataType.getSignature()).to.be.equal(signature); + }); + }); + + describe('Function', () => { + it('No inputs and no outputs', async () => { + // create encoder + const functionName = 'foo'; + const dataType = AbiEncoder.createMethod(functionName); + // create expected values + const expectedSignature = 'foo()'; + const expectedInputDataItem = { + name: 'foo', + type: 'method', + components: [], + }; + const expectedOutputDataItem = { + name: 'foo', + type: 'tuple', + components: [], + }; + // check expected values + expect(dataType.getSignature()).to.be.equal(expectedSignature); + expect(dataType.getDataItem()).to.be.deep.equal(expectedInputDataItem); + expect(dataType.getReturnValueDataItem()).to.be.deep.equal(expectedOutputDataItem); + }); + it('No inputs and no outputs (empty arrays as input)', async () => { + // create encoder + const functionName = 'foo'; + const dataType = AbiEncoder.createMethod(functionName, [], []); + // create expected values + const expectedSignature = 'foo()'; + const expectedInputDataItem = { + name: 'foo', + type: 'method', + components: [], + }; + const expectedOutputDataItem = { + name: 'foo', + type: 'tuple', + components: [], + }; + // check expected values + expect(dataType.getSignature()).to.be.equal(expectedSignature); + expect(dataType.getDataItem()).to.be.deep.equal(expectedInputDataItem); + expect(dataType.getReturnValueDataItem()).to.be.deep.equal(expectedOutputDataItem); + }); + it('Single DataItem input and single DataItem output', async () => { + // create encoder + const functionName = 'foo'; + const inputDataItem = { + name: 'input', + type: 'uint256', + }; + const outputDataItem = { + name: 'output', + type: 'string', + }; + const dataType = AbiEncoder.createMethod(functionName, inputDataItem, outputDataItem); + // create expected values + const expectedSignature = 'foo(uint256)'; + const expectedInputDataItem = { + name: 'foo', + type: 'method', + components: [inputDataItem], + }; + const expectedOutputDataItem = { + name: 'foo', + type: 'tuple', + components: [outputDataItem], + }; + // check expected values + expect(dataType.getSignature()).to.be.equal(expectedSignature); + expect(dataType.getDataItem()).to.be.deep.equal(expectedInputDataItem); + expect(dataType.getReturnValueDataItem()).to.be.deep.equal(expectedOutputDataItem); + }); + it('Single signature input and single signature output', async () => { + // create encoder + const functionName = 'foo'; + const inputSignature = 'uint256'; + const outputSignature = 'string'; + const dataType = AbiEncoder.createMethod(functionName, inputSignature, outputSignature); + // create expected values + const expectedSignature = 'foo(uint256)'; + const expectedInputDataItem = { + name: 'foo', + type: 'method', + components: [ + { + name: '', + type: 'uint256', + }, + ], + }; + const expectedOutputDataItem = { + name: 'foo', + type: 'tuple', + components: [ + { + name: '', + type: 'string', + }, + ], + }; + // check expected values + expect(dataType.getSignature()).to.be.equal(expectedSignature); + expect(dataType.getDataItem()).to.be.deep.equal(expectedInputDataItem); + expect(dataType.getReturnValueDataItem()).to.be.deep.equal(expectedOutputDataItem); + }); + it('Single signature tuple input and single signature tuple output', async () => { + // create encoder + const functionName = 'foo'; + const inputSignature = '(uint256,bytes[][4])'; + const outputSignature = '(string,uint32)'; + const dataType = AbiEncoder.createMethod(functionName, inputSignature, outputSignature); + // create expected values + const expectedSignature = 'foo((uint256,bytes[][4]))'; + const expectedInputDataItem = { + name: 'foo', + type: 'method', + components: [ + { + name: '', + type: 'tuple', + components: [ + { + name: '', + type: 'uint256', + }, + { + name: '', + type: 'bytes[][4]', + }, + ], + }, + ], + }; + const expectedOutputDataItem = { + name: 'foo', + type: 'tuple', + components: [ + { + name: '', + type: 'tuple', + components: [ + { + name: '', + type: 'string', + }, + { + name: '', + type: 'uint32', + }, + ], + }, + ], + }; + // check expected values + expect(dataType.getSignature()).to.be.equal(expectedSignature); + expect(dataType.getDataItem()).to.be.deep.equal(expectedInputDataItem); + expect(dataType.getReturnValueDataItem()).to.be.deep.equal(expectedOutputDataItem); + }); + it('Mutiple DataItem input and multiple DataItem output', async () => { + // create encoder + const functionName = 'foo'; + const inputDataItems = [ + { + name: '', + type: 'uint256', + }, + { + name: '', + type: 'bytes[][4]', + }, + ]; + const outputDataItems = [ + { + name: '', + type: 'string', + }, + { + name: '', + type: 'uint32', + }, + ]; + const dataType = AbiEncoder.createMethod(functionName, inputDataItems, outputDataItems); + // create expected values + const expectedSignature = 'foo(uint256,bytes[][4])'; + const expectedInputDataItem = { + name: 'foo', + type: 'method', + components: inputDataItems, + }; + const expectedOutputDataItem = { + name: 'foo', + type: 'tuple', + components: outputDataItems, + }; + // check expected values + expect(dataType.getSignature()).to.be.equal(expectedSignature); + expect(dataType.getDataItem()).to.be.deep.equal(expectedInputDataItem); + expect(dataType.getReturnValueDataItem()).to.be.deep.equal(expectedOutputDataItem); + }); + it('Multiple signature input and multiple signature output', async () => { + // create encoder + const functionName = 'foo'; + const inputSignatures = ['uint256', 'bytes[][4]']; + const outputSignatures = ['string', 'uint32']; + const dataType = AbiEncoder.createMethod(functionName, inputSignatures, outputSignatures); + // create expected values + const expectedSignature = 'foo(uint256,bytes[][4])'; + const expectedInputDataItem = { + name: 'foo', + type: 'method', + components: [ + { + name: '', + type: 'uint256', + }, + { + name: '', + type: 'bytes[][4]', + }, + ], + }; + const expectedOutputDataItem = { + name: 'foo', + type: 'tuple', + components: [ + { + name: '', + type: 'string', + }, + { + name: '', + type: 'uint32', + }, + ], + }; + // check expected values + expect(dataType.getSignature()).to.be.equal(expectedSignature); + expect(dataType.getDataItem()).to.be.deep.equal(expectedInputDataItem); + expect(dataType.getReturnValueDataItem()).to.be.deep.equal(expectedOutputDataItem); + }); + }); +}); diff --git a/packages/utils/test/abi_encoder/signature_tests.ts b/packages/utils/test/abi_encoder/signature_tests.ts deleted file mode 100644 index e69de29bb2..0000000000 From 21c3f75efcae5fd4f59df3dffe0af0ec59a163a7 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 11:57:09 -0800 Subject: [PATCH 08/39] Changelog for utils package --- packages/utils/CHANGELOG.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index 007591d181..9ce2a4c52f 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "4.0.4", + "changes": [ + { + "note": "Cleaner signature parsing", + "pr": 1592 + } + ] + }, { "version": "4.0.3", "changes": [ From b9ee9d2bd5b6aac11ccea5a71291e8885bbe6f7a Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 7 Feb 2019 14:59:56 -0800 Subject: [PATCH 09/39] replaced typeof with _.isString --- packages/utils/src/abi_encoder/evm_data_type_factory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts index 613eb887f1..8e477f8569 100644 --- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts +++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts @@ -159,7 +159,7 @@ function consolidateDataItemsIntoSingle(input: DataItem | DataItem[] | string): components: dataItems, }; } else { - dataItem = typeof input === 'string' ? generateDataItemFromSignature(input) : (input as DataItem); + dataItem = _.isString(input) ? generateDataItemFromSignature(input) : (input as DataItem); } return dataItem; } @@ -201,7 +201,7 @@ function consolidateDataItemsIntoArray(input: DataItem | DataItem[] | string | s let dataItems: DataItem[]; if (_.isArray(input) && _.isEmpty(input)) { dataItems = []; - } else if (_.isArray(input) && typeof input[0] === 'string') { + } else if (_.isArray(input) && _.isString(input[0])) { dataItems = []; _.each(input as string[], (signature: string) => { const dataItem = generateDataItemFromSignature(signature); From f3716fd813952396aafed7e8bb92e6b4d63ecb7e Mon Sep 17 00:00:00 2001 From: David Sun Date: Thu, 7 Feb 2019 20:41:37 -0500 Subject: [PATCH 10/39] fixed config orderSource assignment --- packages/instant/src/index.umd.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 7b2b45a714..243bb569b8 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -94,21 +94,24 @@ export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { } export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { - if (_.isArray(config.orderSource)) { - config.orderSource = orderCoercionUtil.coerceOrderArrayFieldsToBigNumber(config.orderSource); - } + // Coerces BigNumber provided in config to version utilized by 0x packages + const coercedConfig = _.assign({}, config, { + orderSource: _.isArray(config.orderSource) + ? orderCoercionUtil.coerceOrderArrayFieldsToBigNumber(config.orderSource) + : config.orderSource, + }); - validateInstantRenderConfig(config, selector); + validateInstantRenderConfig(coercedConfig, selector); - if (config.shouldDisablePushToHistory) { + if (coercedConfig.shouldDisablePushToHistory) { if (!isInstantRendered()) { - renderInstant(config, selector); + renderInstant(coercedConfig, selector); } return; } // Before we render, push to history saying that instant is showing for this part of the history. window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); - let removeInstant = renderInstant(config, selector); + let removeInstant = renderInstant(coercedConfig, selector); // If the integrator defined a popstate handler, save it to __zeroExInstantIntegratorsPopStateHandler // unless we have already done so on a previous render. const anyWindow = window as any; @@ -122,7 +125,7 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z if (newState && newState.zeroExInstantShowing) { // We have returned to a history state that expects instant to be rendered. if (!isInstantRendered()) { - removeInstant = renderInstant(config, selector); + removeInstant = renderInstant(coercedConfig, selector); } } else { // History has changed to a different state. From d01837f42c0aaace6248b1a246b55b929a575562 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 8 Feb 2019 13:19:47 +0000 Subject: [PATCH 11/39] Allow using Web3Factory in-process Ganache with existing snapshot --- packages/dev-utils/src/web3_factory.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/dev-utils/src/web3_factory.ts b/packages/dev-utils/src/web3_factory.ts index 5f8981a467..3fa3c19f70 100644 --- a/packages/dev-utils/src/web3_factory.ts +++ b/packages/dev-utils/src/web3_factory.ts @@ -47,8 +47,11 @@ export const web3Factory = { _.isUndefined(config.shouldThrowErrorsOnGanacheRPCResponse) || config.shouldThrowErrorsOnGanacheRPCResponse; if (!_.isUndefined(config.ganacheDatabasePath)) { - // Saving the snapshot to a local db. Ganache requires this directory to exist - fs.mkdirSync(config.ganacheDatabasePath); + const doesDatabaseAlreadyExist = fs.existsSync(config.ganacheDatabasePath); + if (!doesDatabaseAlreadyExist) { + // Working with local DB snapshot. Ganache requires this directory to exist + fs.mkdirSync(config.ganacheDatabasePath); + } } provider.addProvider( new GanacheSubprovider({ From c794153221af10446e3a9316037451fa1c6dbfdb Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 8 Feb 2019 13:22:11 +0000 Subject: [PATCH 12/39] Add CHANGELOG entry --- packages/dev-utils/CHANGELOG.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json index ce6cfede53..cbeb2e74f3 100644 --- a/packages/dev-utils/CHANGELOG.json +++ b/packages/dev-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "2.1.0", + "changes": [ + { + "note": "Allow using the Web3Factory in-process Ganache provider with existing DB snapshot", + "pr": 1602 + } + ] + }, { "version": "2.0.2", "changes": [ From 629a8d632801c4861824b7d0423792d167b8564d Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Fri, 8 Feb 2019 13:21:41 -0500 Subject: [PATCH 13/39] Add migration to fix exchange events primary keys (#1593) * Add migration to fix exchange events primary key * correct comment: "foreign key" -> "primary key" * Refine hack to handle only the expected error * Add tx hash to erc20 approval events primary key --- ...2800-AddTxHashToExchangeEventPrimaryKey.ts | 35 +++++++++++++++++++ ...AddTxHashToERC20ApprovalEventPrimaryKey.ts | 31 ++++++++++++++++ .../src/entities/erc20_approval_event.ts | 2 +- .../src/entities/exchange_cancel_event.ts | 2 +- .../entities/exchange_cancel_up_to_event.ts | 2 +- .../src/entities/exchange_fill_event.ts | 2 +- .../src/scripts/pull_exchange_events.ts | 12 +++++-- 7 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 packages/pipeline/migrations/1549479172800-AddTxHashToExchangeEventPrimaryKey.ts create mode 100644 packages/pipeline/migrations/1549499426238-AddTxHashToERC20ApprovalEventPrimaryKey.ts diff --git a/packages/pipeline/migrations/1549479172800-AddTxHashToExchangeEventPrimaryKey.ts b/packages/pipeline/migrations/1549479172800-AddTxHashToExchangeEventPrimaryKey.ts new file mode 100644 index 0000000000..d6ea6c47b7 --- /dev/null +++ b/packages/pipeline/migrations/1549479172800-AddTxHashToExchangeEventPrimaryKey.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +const tableNames = ['exchange_cancel_events', 'exchange_cancel_up_to_events', 'exchange_fill_events']; + +const oldPrimaryColumns = ['contract_address', 'log_index', 'block_number']; + +const newPrimaryColumns = ['transaction_hash']; + +async function updatePrimaryKeysAsync(queryRunner: QueryRunner, columnNames: string[]): Promise { + for (const tableName of tableNames) { + const table = await queryRunner.getTable(`raw.${tableName}`); + if (table === undefined) { + throw new Error(`Couldn't get table 'raw.${tableName}'`); + } + const columns = []; + for (const columnName of columnNames) { + const column = table.findColumnByName(columnName); + if (column === undefined) { + throw new Error(`Couldn't get column '${columnName}' from table 'raw.${tableName}'`); + } + columns.push(column); + } + await queryRunner.updatePrimaryKeys(table, columns); + } +} + +export class AddTxHashToExchangeEventPrimaryKey1549479172800 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await updatePrimaryKeysAsync(queryRunner, oldPrimaryColumns.concat(newPrimaryColumns)); + } + + public async down(queryRunner: QueryRunner): Promise { + await updatePrimaryKeysAsync(queryRunner, oldPrimaryColumns); + } +} diff --git a/packages/pipeline/migrations/1549499426238-AddTxHashToERC20ApprovalEventPrimaryKey.ts b/packages/pipeline/migrations/1549499426238-AddTxHashToERC20ApprovalEventPrimaryKey.ts new file mode 100644 index 0000000000..874713e670 --- /dev/null +++ b/packages/pipeline/migrations/1549499426238-AddTxHashToERC20ApprovalEventPrimaryKey.ts @@ -0,0 +1,31 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +const oldPrimaryColumns = ['token_address', 'log_index', 'block_number']; + +const newPrimaryColumns = ['transaction_hash']; + +async function updatePrimaryKeysAsync(queryRunner: QueryRunner, columnNames: string[]): Promise { + const table = await queryRunner.getTable(`raw.erc20_approval_events`); + if (table === undefined) { + throw new Error(`Couldn't get table 'raw.erc20_approval_events'`); + } + const columns = []; + for (const columnName of columnNames) { + const column = table.findColumnByName(columnName); + if (column === undefined) { + throw new Error(`Couldn't get column '${columnName}' from table 'raw.erc20_approval_events'`); + } + columns.push(column); + } + await queryRunner.updatePrimaryKeys(table, columns); +} + +export class AddTxHashToERC20ApprovalEventPrimaryKey1549499426238 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await updatePrimaryKeysAsync(queryRunner, oldPrimaryColumns.concat(newPrimaryColumns)); + } + + public async down(queryRunner: QueryRunner): Promise { + await updatePrimaryKeysAsync(queryRunner, oldPrimaryColumns); + } +} diff --git a/packages/pipeline/src/entities/erc20_approval_event.ts b/packages/pipeline/src/entities/erc20_approval_event.ts index 69cdfcb0b6..ee5e621d23 100644 --- a/packages/pipeline/src/entities/erc20_approval_event.ts +++ b/packages/pipeline/src/entities/erc20_approval_event.ts @@ -15,7 +15,7 @@ export class ERC20ApprovalEvent { @Column({ name: 'raw_data' }) public rawData!: string; - @Column({ name: 'transaction_hash' }) + @PrimaryColumn({ name: 'transaction_hash' }) public transactionHash!: string; @Column({ name: 'owner_address' }) public ownerAddress!: string; diff --git a/packages/pipeline/src/entities/exchange_cancel_event.ts b/packages/pipeline/src/entities/exchange_cancel_event.ts index 38f99c9033..a861949201 100644 --- a/packages/pipeline/src/entities/exchange_cancel_event.ts +++ b/packages/pipeline/src/entities/exchange_cancel_event.ts @@ -15,7 +15,7 @@ export class ExchangeCancelEvent { @Column({ name: 'raw_data' }) public rawData!: string; - @Column({ name: 'transaction_hash' }) + @PrimaryColumn({ name: 'transaction_hash' }) public transactionHash!: string; @Column({ name: 'maker_address' }) public makerAddress!: string; diff --git a/packages/pipeline/src/entities/exchange_cancel_up_to_event.ts b/packages/pipeline/src/entities/exchange_cancel_up_to_event.ts index 27580305e9..f24aea23ad 100644 --- a/packages/pipeline/src/entities/exchange_cancel_up_to_event.ts +++ b/packages/pipeline/src/entities/exchange_cancel_up_to_event.ts @@ -15,7 +15,7 @@ export class ExchangeCancelUpToEvent { @Column({ name: 'raw_data' }) public rawData!: string; - @Column({ name: 'transaction_hash' }) + @PrimaryColumn({ name: 'transaction_hash' }) public transactionHash!: string; @Column({ name: 'maker_address' }) public makerAddress!: string; diff --git a/packages/pipeline/src/entities/exchange_fill_event.ts b/packages/pipeline/src/entities/exchange_fill_event.ts index 9b7727615a..52111711eb 100644 --- a/packages/pipeline/src/entities/exchange_fill_event.ts +++ b/packages/pipeline/src/entities/exchange_fill_event.ts @@ -16,7 +16,7 @@ export class ExchangeFillEvent { @Column({ name: 'raw_data' }) public rawData!: string; - @Column({ name: 'transaction_hash' }) + @PrimaryColumn({ name: 'transaction_hash' }) public transactionHash!: string; @Column({ name: 'maker_address' }) public makerAddress!: string; diff --git a/packages/pipeline/src/scripts/pull_exchange_events.ts b/packages/pipeline/src/scripts/pull_exchange_events.ts index f8ce4038de..c2c56da6b0 100644 --- a/packages/pipeline/src/scripts/pull_exchange_events.ts +++ b/packages/pipeline/src/scripts/pull_exchange_events.ts @@ -112,15 +112,20 @@ async function saveIndividuallyWithFallbackAsync( events: T[], ): Promise { // Note(albrow): This is a temporary hack because `save` is not working as - // documented and is causing a foreign key constraint violation. Hopefully + // documented and is causing a primary key constraint violation. Hopefully // can remove later because this "poor man's upsert" implementation operates // on one event at a time and is therefore much slower. for (const event of events) { try { // First try an insert. await repository.insert(event); - } catch { - // If it fails, assume it was a foreign key constraint error and try + } catch (err) { + if (err.message.includes('duplicate key value violates unique constraint')) { + logUtils.log("Ignore the preceeding INSERT failure; it's not unexpected"); + } else { + throw err; + } + // If it fails, assume it was a primary key constraint error and try // doing an update instead. // Note(albrow): Unfortunately the `as any` hack here seems // required. I can't figure out how to convince the type-checker @@ -132,6 +137,7 @@ async function saveIndividuallyWithFallbackAsync( contractAddress: event.contractAddress, blockNumber: event.blockNumber, logIndex: event.logIndex, + transactionHash: event.transactionHash, } as any, event as any, ); From 100840b74359e00bda90146f87ddeafd62db06e3 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 29 Jan 2019 17:18:33 -0800 Subject: [PATCH 14/39] Utility function to decode arbitrary 0x calldata --- packages/utils/package.json | 2 +- packages/utils/src/calldata_decoder.ts | 66 ++++++++++++++++++++ packages/utils/src/index.ts | 1 + packages/utils/test/calldata_decoder_test.ts | 21 +++++++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 packages/utils/src/calldata_decoder.ts create mode 100644 packages/utils/test/calldata_decoder_test.ts diff --git a/packages/utils/package.json b/packages/utils/package.json index 86fecbc7c4..895560961f 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -14,7 +14,7 @@ "lint": "tslint --format stylish --project .", "test": "yarn run_mocha", "test:circleci": "yarn test:coverage", - "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --bail --exit", + "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*_test.js' 'lib/test/*_test.js' --bail --exit", "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info" }, diff --git a/packages/utils/src/calldata_decoder.ts b/packages/utils/src/calldata_decoder.ts new file mode 100644 index 0000000000..780332514d --- /dev/null +++ b/packages/utils/src/calldata_decoder.ts @@ -0,0 +1,66 @@ +// Decodes any 0x transaction + +import * as ContractArtifacts from '@0x/contract-artifacts'; +import { SimpleContractArtifact } from '@0x/types'; +import { ContractAbi, MethodAbi } from 'ethereum-types'; +import * as _ from 'lodash'; +import { AbiEncoder } from '.'; + +export interface DecodedCalldata { + functionName: string; + functionSignature: string; + functionArguments: any; +} + +interface AbiEncoderBySelector { + [index: string]: AbiEncoder.Method; +} + +export class CalldataDecoder { + private readonly _abiEncoderBySelector: AbiEncoderBySelector = {}; + private static _instance: CalldataDecoder; + + public static getInstance(): CalldataDecoder { + if (!CalldataDecoder._instance) { + CalldataDecoder._instance = new CalldataDecoder(); + } + return CalldataDecoder._instance; + } + + public constructor() { + _.each(ContractArtifacts, (contractArtifactAsJson: any) => { + const conractArtifact = contractArtifactAsJson as SimpleContractArtifact; + const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; + const functionAbis = _.filter(contractAbi, (abiEntry) => {return abiEntry.type === 'function'}) as MethodAbi[]; + _.each(functionAbis, (functionAbi) => { + const abiEncoder = new AbiEncoder.Method(functionAbi); + const functionSelector = abiEncoder.getSelector(); + if (_.has(this._abiEncoderBySelector, functionSelector)) { + return; + } + this._abiEncoderBySelector[functionSelector] = abiEncoder; + }); + }); + } + + public static decode(calldata: string, rules?: AbiEncoder.DecodingRules): DecodedCalldata { + if (!calldata.startsWith('0x') || calldata.length < 10) { + throw new Error(`Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`); + } + const functionSelector = calldata.substr(0, 10); + const instance = CalldataDecoder.getInstance(); + const abiEncoder = instance._abiEncoderBySelector[functionSelector]; + if (_.isUndefined(abiEncoder)) { + throw new Error(`Could not find matching abi encoder for selector '${functionSelector}'`); + } + const functionName = abiEncoder.getDataItem().name; + const functionSignature = abiEncoder.getSignatureType(); + const functionArguments = abiEncoder.decode(calldata, rules); + const decodedCalldata = { + functionName, + functionSignature, + functionArguments + } + return decodedCalldata; + } +} \ No newline at end of file diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 082aff6bbe..3e5058edc3 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -11,3 +11,4 @@ export { errorUtils } from './error_utils'; export { fetchAsync } from './fetch_async'; export { signTypedDataUtils } from './sign_typed_data_utils'; export import AbiEncoder = require('./abi_encoder'); +export { CalldataDecoder } from './calldata_decoder'; diff --git a/packages/utils/test/calldata_decoder_test.ts b/packages/utils/test/calldata_decoder_test.ts new file mode 100644 index 0000000000..a3ff02a593 --- /dev/null +++ b/packages/utils/test/calldata_decoder_test.ts @@ -0,0 +1,21 @@ +import * as chai from 'chai'; +import 'mocha'; + +import { CalldataDecoder } from '../src'; +import { chaiSetup } from './utils/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe.only('CalldataDecoder', () => { + describe.only('decodeCalldata', () => { + it.only('should successfull decode fillOrder calldata', async () => { + //const cancelCalldata = '0xd46b02c3000000000000000000000000000000000000000000000000000000000000002000000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a258b39954cef5cb142fd567a46cddb31a6701240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071d75ab9b9204fffc40000000000000000000000000000000000000000000000011c6e19c53d35b66200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c50f2ed000000000000000000000000000000000000000000000000000001689c2bc812000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000'; + //const marketBuycalldata = '0xe5fa431b0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008c26348f63f9e008f0dd09a0ce1ed7caf6c1366b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e150a33ffa97a8d22f59c77ae5487b089ef62e90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000001323e717ba3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ea9bd19a0c4b5533ac98f58db0558a96e15ec5f71d64b6070cea4b5df10b7fb35424035000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000006cb262679c522c4f0834041a6248e8feb35f0337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000421c750cedbf0eef0914c09b296f08462c363527f454bcf2dfaaf2f772e290d0ee5b0417d8b95837cbe501494195edc2a5a48c664d2ef74a340e40213c05db8767fa03000000000000000000000000000000000000000000000000000000000000'; + const calldata = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; + const decodedCalldata = CalldataDecoder.decode(calldata); + console.log(JSON.stringify(decodedCalldata, null, 4)); + expect(5).to.be.equal(5); + }); + }); +}); From 8fc3a6b828e6f3a5f1aacfc62f585834f012ce7a Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 30 Jan 2019 10:52:13 -0800 Subject: [PATCH 15/39] Expanding search parameters for transaction decoder --- packages/utils/src/calldata_decoder.ts | 93 ++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/packages/utils/src/calldata_decoder.ts b/packages/utils/src/calldata_decoder.ts index 780332514d..0279aa0301 100644 --- a/packages/utils/src/calldata_decoder.ts +++ b/packages/utils/src/calldata_decoder.ts @@ -5,18 +5,41 @@ import { SimpleContractArtifact } from '@0x/types'; import { ContractAbi, MethodAbi } from 'ethereum-types'; import * as _ from 'lodash'; import { AbiEncoder } from '.'; +import { ContractAddresses, getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses'; export interface DecodedCalldata { functionName: string; functionSignature: string; functionArguments: any; + contractName: string; + deployedAddress?: string; + deployedNeworkId?: string; +} + +interface AbiEncoderBySelectorElement { + abiEncoder: AbiEncoder.Method; + contractName?: string; + contractAddress?: string; +} + +interface AbiEncoderByNeworkId { + [index: string]: AbiEncoderBySelectorElement; } interface AbiEncoderBySelector { - [index: string]: AbiEncoder.Method; + [index: string]: AbiEncoderByNeworkId; +} + +interface DeployedContractInfoByNetwork { + [index: number]: string; +} + +interface DeployedContractInfoByName { + [index: string]: DeployedContractInfoByNetwork; } export class CalldataDecoder { + private readonly _deployedContractInfoByName = {} as DeployedContractInfoByName; private readonly _abiEncoderBySelector: AbiEncoderBySelector = {}; private static _instance: CalldataDecoder; @@ -27,7 +50,15 @@ export class CalldataDecoder { return CalldataDecoder._instance; } - public constructor() { + private constructor() { + // Load addresses by contract name + _.each(NetworkId, (networkId: NetworkId) => { + const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkId); + _.each(contractAddressesForNetwork, (contractAddress: string, contractName: string) => { + this._deployedContractInfoByName[contractName][networkId as number] = contractAddress; + }); + }); + // Load contract artifacts _.each(ContractArtifacts, (contractArtifactAsJson: any) => { const conractArtifact = contractArtifactAsJson as SimpleContractArtifact; const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; @@ -38,21 +69,71 @@ export class CalldataDecoder { if (_.has(this._abiEncoderBySelector, functionSelector)) { return; } - this._abiEncoderBySelector[functionSelector] = abiEncoder; + this._abiEncoderBySelector[functionSelector][conractArtifact.contractName] = {abiEncoder}; }); }); } - public static decode(calldata: string, rules?: AbiEncoder.DecodingRules): DecodedCalldata { + public static registerContractAbi(contractArtifact: SimpleContractArtifact, deployedAddress?: string, deployedNeworkId?: number) { + + } + + private static getFunctionSelector(calldata: string): string { if (!calldata.startsWith('0x') || calldata.length < 10) { throw new Error(`Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`); } const functionSelector = calldata.substr(0, 10); + return functionSelector; + } + + public static decodeWithContractAddress(calldata: string, contractAddress: string, networkId?: number): DecodedCalldata { + const functionSelector = CalldataDecoder.getFunctionSelector(calldata); const instance = CalldataDecoder.getInstance(); - const abiEncoder = instance._abiEncoderBySelector[functionSelector]; + const contractName = _.findKey(instance._deployedContractInfoByName, (info: DeployedContractInfoByNetwork) => { + return (!_.isUndefined(networkId) && info[networkId] === contractAddress) || (_.isUndefined(networkId) && contractAddress in info); + }); + if (_.isUndefined(contractName)) { + throw new Error(`Could not find contract name: ${contractName}`); + } + const abiEncoder = instance._abiEncoderBySelector[functionSelector][contractName]; if (_.isUndefined(abiEncoder)) { throw new Error(`Could not find matching abi encoder for selector '${functionSelector}'`); } + + } + + public static decodeWithContractName(calldata: string, contractName: string): DecodedCalldata { + const functionSelector = CalldataDecoder.getFunctionSelector(calldata); + const instance = CalldataDecoder.getInstance(); + const abiEncoder = instance._abiEncoderBySelector[functionSelector][contractName]; + if (_.isUndefined(abiEncoder)) { + throw new Error(`Could not find matching abi encoder for selector '${functionSelector}'`); + } + } + + public static decodeWithoutContractInfo(calldata: string): DecodedCalldata { + const functionSelector = CalldataDecoder.getFunctionSelector(calldata); + const instance = CalldataDecoder.getInstance(); + const abiEncoder = _.find(instance._abiEncoderBySelector[functionSelector], () => {return true}); + if (_.isUndefined(abiEncoder)) { + throw new Error(`Could not find matching abi encoder for selector '${functionSelector}'`); + } + return { + functionName: string; + functionSignature: string; + functionArguments: any; + contractName: string; + deployedAddress?: string; + deployedNeworkId?: string; + }; + } + + public static decode(calldata: string, contractName?: string, contractAddress?: string, networkId?: number, rules?: AbiEncoder.DecodingRules): DecodedCalldata { + + + + + /* const functionName = abiEncoder.getDataItem().name; const functionSignature = abiEncoder.getSignatureType(); const functionArguments = abiEncoder.decode(calldata, rules); @@ -61,6 +142,6 @@ export class CalldataDecoder { functionSignature, functionArguments } - return decodedCalldata; + return decodedCalldata;*/ } } \ No newline at end of file From f93cd1bb48c9ae977822a274033f02fab737f64a Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 30 Jan 2019 12:28:09 -0800 Subject: [PATCH 16/39] Can query decoder by contract address / network id OR contract name --- packages/utils/src/calldata_decoder.ts | 129 ++++++++++--------- packages/utils/test/calldata_decoder_test.ts | 2 +- 2 files changed, 68 insertions(+), 63 deletions(-) diff --git a/packages/utils/src/calldata_decoder.ts b/packages/utils/src/calldata_decoder.ts index 0279aa0301..bbd67fd2c5 100644 --- a/packages/utils/src/calldata_decoder.ts +++ b/packages/utils/src/calldata_decoder.ts @@ -11,15 +11,26 @@ export interface DecodedCalldata { functionName: string; functionSignature: string; functionArguments: any; - contractName: string; - deployedAddress?: string; - deployedNeworkId?: string; } interface AbiEncoderBySelectorElement { abiEncoder: AbiEncoder.Method; contractName?: string; contractAddress?: string; + networkId?: number; +} + +interface TransactionDecoderInfo { + abiEncoder: AbiEncoder.Method; + contractName?: string; + contractAddress?: string; + networkId?: number; +} + +interface TransactionProperties { + contractName?: string; + contractAddress?: string; + networkId?: number; } interface AbiEncoderByNeworkId { @@ -30,17 +41,23 @@ interface AbiEncoderBySelector { [index: string]: AbiEncoderByNeworkId; } -interface DeployedContractInfoByNetwork { - [index: number]: string; +interface DeployedContractInfo { + contractAddress?: string; + networkId?: number; } interface DeployedContractInfoByName { - [index: string]: DeployedContractInfoByNetwork; + [index: string]: DeployedContractInfo[]; +} + +interface TransactionDecodersBySelector { + [index: string]: TransactionDecoderInfo[]; } export class CalldataDecoder { private readonly _deployedContractInfoByName = {} as DeployedContractInfoByName; private readonly _abiEncoderBySelector: AbiEncoderBySelector = {}; + private readonly _txDecoders: TransactionDecodersBySelector = {}; private static _instance: CalldataDecoder; public static getInstance(): CalldataDecoder { @@ -52,15 +69,23 @@ export class CalldataDecoder { private constructor() { // Load addresses by contract name - _.each(NetworkId, (networkId: NetworkId) => { - const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkId); + _.each(NetworkId, (networkId: any) => { + if (typeof networkId !== 'number') return; + const networkIdAsNumber = networkId as number; + const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkIdAsNumber); _.each(contractAddressesForNetwork, (contractAddress: string, contractName: string) => { - this._deployedContractInfoByName[contractName][networkId as number] = contractAddress; + const contractNameLowercase = _.toLower(contractName); + if (_.isUndefined(this._deployedContractInfoByName[contractNameLowercase])) { + this._deployedContractInfoByName[contractNameLowercase] = []; + } + this._deployedContractInfoByName[contractNameLowercase].push({contractAddress, networkId: networkIdAsNumber}); }); }); // Load contract artifacts _.each(ContractArtifacts, (contractArtifactAsJson: any) => { const conractArtifact = contractArtifactAsJson as SimpleContractArtifact; + const contractName = conractArtifact.contractName; + const contractNameLowercase = _.toLower(contractName); const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; const functionAbis = _.filter(contractAbi, (abiEntry) => {return abiEntry.type === 'function'}) as MethodAbi[]; _.each(functionAbis, (functionAbi) => { @@ -69,15 +94,27 @@ export class CalldataDecoder { if (_.has(this._abiEncoderBySelector, functionSelector)) { return; } - this._abiEncoderBySelector[functionSelector][conractArtifact.contractName] = {abiEncoder}; + if (!(functionSelector in this._txDecoders)) this._txDecoders[functionSelector] = []; + // Recored deployed versions of this decoder + _.each(this._deployedContractInfoByName[contractNameLowercase], (deployedContract) => { + this._txDecoders[functionSelector].push({ + abiEncoder, + contractName, + contractAddress: deployedContract.contractAddress, + networkId: deployedContract.networkId, + }); + }); + // If there isn't a deployed version of this contract, record it without address/network id + if (_.isUndefined(this._deployedContractInfoByName[contractNameLowercase])) { + this._txDecoders[functionSelector].push({ + abiEncoder, + contractName, + }); + } }); }); } - public static registerContractAbi(contractArtifact: SimpleContractArtifact, deployedAddress?: string, deployedNeworkId?: number) { - - } - private static getFunctionSelector(calldata: string): string { if (!calldata.startsWith('0x') || calldata.length < 10) { throw new Error(`Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`); @@ -86,62 +123,30 @@ export class CalldataDecoder { return functionSelector; } - public static decodeWithContractAddress(calldata: string, contractAddress: string, networkId?: number): DecodedCalldata { + public static decode(calldata: string, txProperties_?: TransactionProperties): DecodedCalldata { const functionSelector = CalldataDecoder.getFunctionSelector(calldata); + const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; const instance = CalldataDecoder.getInstance(); - const contractName = _.findKey(instance._deployedContractInfoByName, (info: DeployedContractInfoByNetwork) => { - return (!_.isUndefined(networkId) && info[networkId] === contractAddress) || (_.isUndefined(networkId) && contractAddress in info); + const txDecodersByFunctionSelector = instance._txDecoders[functionSelector]; + if (_.isUndefined(txDecodersByFunctionSelector)) { + throw new Error(`No decoder registered for function selector '${functionSelector}'`); + } + const txDecoderWithProperties = _.find(txDecodersByFunctionSelector, (txDecoder) => { + return (_.isUndefined(txProperties.contractName) || _.toLower(txDecoder.contractName) === _.toLower(txProperties.contractName)) && + (_.isUndefined(txProperties.contractAddress) || txDecoder.contractAddress === txProperties.contractAddress) && + (_.isUndefined(txProperties.networkId) || txDecoder.networkId === txProperties.networkId); }); - if (_.isUndefined(contractName)) { - throw new Error(`Could not find contract name: ${contractName}`); + if (_.isUndefined(txDecoderWithProperties)) { + throw new Error(`No decoder registered with properties: ${JSON.stringify(txProperties)}.`); } - const abiEncoder = instance._abiEncoderBySelector[functionSelector][contractName]; - if (_.isUndefined(abiEncoder)) { - throw new Error(`Could not find matching abi encoder for selector '${functionSelector}'`); - } - - } - - public static decodeWithContractName(calldata: string, contractName: string): DecodedCalldata { - const functionSelector = CalldataDecoder.getFunctionSelector(calldata); - const instance = CalldataDecoder.getInstance(); - const abiEncoder = instance._abiEncoderBySelector[functionSelector][contractName]; - if (_.isUndefined(abiEncoder)) { - throw new Error(`Could not find matching abi encoder for selector '${functionSelector}'`); - } - } - - public static decodeWithoutContractInfo(calldata: string): DecodedCalldata { - const functionSelector = CalldataDecoder.getFunctionSelector(calldata); - const instance = CalldataDecoder.getInstance(); - const abiEncoder = _.find(instance._abiEncoderBySelector[functionSelector], () => {return true}); - if (_.isUndefined(abiEncoder)) { - throw new Error(`Could not find matching abi encoder for selector '${functionSelector}'`); - } - return { - functionName: string; - functionSignature: string; - functionArguments: any; - contractName: string; - deployedAddress?: string; - deployedNeworkId?: string; - }; - } - - public static decode(calldata: string, contractName?: string, contractAddress?: string, networkId?: number, rules?: AbiEncoder.DecodingRules): DecodedCalldata { - - - - - /* - const functionName = abiEncoder.getDataItem().name; - const functionSignature = abiEncoder.getSignatureType(); - const functionArguments = abiEncoder.decode(calldata, rules); + const functionName = txDecoderWithProperties.abiEncoder.getDataItem().name; + const functionSignature = txDecoderWithProperties.abiEncoder.getSignatureType(); + const functionArguments = txDecoderWithProperties.abiEncoder.decode(calldata); const decodedCalldata = { functionName, functionSignature, functionArguments } - return decodedCalldata;*/ + return decodedCalldata; } } \ No newline at end of file diff --git a/packages/utils/test/calldata_decoder_test.ts b/packages/utils/test/calldata_decoder_test.ts index a3ff02a593..7d5cc9fd92 100644 --- a/packages/utils/test/calldata_decoder_test.ts +++ b/packages/utils/test/calldata_decoder_test.ts @@ -13,7 +13,7 @@ describe.only('CalldataDecoder', () => { //const cancelCalldata = '0xd46b02c3000000000000000000000000000000000000000000000000000000000000002000000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a258b39954cef5cb142fd567a46cddb31a6701240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071d75ab9b9204fffc40000000000000000000000000000000000000000000000011c6e19c53d35b66200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c50f2ed000000000000000000000000000000000000000000000000000001689c2bc812000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000'; //const marketBuycalldata = '0xe5fa431b0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008c26348f63f9e008f0dd09a0ce1ed7caf6c1366b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e150a33ffa97a8d22f59c77ae5487b089ef62e90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000001323e717ba3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ea9bd19a0c4b5533ac98f58db0558a96e15ec5f71d64b6070cea4b5df10b7fb35424035000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000006cb262679c522c4f0834041a6248e8feb35f0337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000421c750cedbf0eef0914c09b296f08462c363527f454bcf2dfaaf2f772e290d0ee5b0417d8b95837cbe501494195edc2a5a48c664d2ef74a340e40213c05db8767fa03000000000000000000000000000000000000000000000000000000000000'; const calldata = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; - const decodedCalldata = CalldataDecoder.decode(calldata); + const decodedCalldata = CalldataDecoder.decode(calldata, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); console.log(JSON.stringify(decodedCalldata, null, 4)); expect(5).to.be.equal(5); }); From a9f8e80b1c5e7be3ca2a4552b67ff3bd39aa23c3 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 31 Jan 2019 11:24:12 -0800 Subject: [PATCH 17/39] Abstractd out ZeroExTransactionDecoder --- packages/utils/src/calldata_decoder.ts | 197 ++++++++++--------- packages/utils/src/index.ts | 2 +- packages/utils/test/calldata_decoder_test.ts | 4 +- 3 files changed, 108 insertions(+), 95 deletions(-) diff --git a/packages/utils/src/calldata_decoder.ts b/packages/utils/src/calldata_decoder.ts index bbd67fd2c5..36016c7bc6 100644 --- a/packages/utils/src/calldata_decoder.ts +++ b/packages/utils/src/calldata_decoder.ts @@ -2,10 +2,22 @@ import * as ContractArtifacts from '@0x/contract-artifacts'; import { SimpleContractArtifact } from '@0x/types'; -import { ContractAbi, MethodAbi } from 'ethereum-types'; +import { AbiDefinition, ContractAbi, MethodAbi } from 'ethereum-types'; import * as _ from 'lodash'; import { AbiEncoder } from '.'; -import { ContractAddresses, getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses'; +import { getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses'; + +export interface FunctionInfo { + functionSignature: string; + contractName?: string; + contractAddress?: string; + networkId?: number; + abiEncoder?: AbiEncoder.Method; +} + +interface FunctionInfoBySelector { + [index: string]: FunctionInfo[]; +} export interface DecodedCalldata { functionName: string; @@ -13,61 +25,110 @@ export interface DecodedCalldata { functionArguments: any; } -interface AbiEncoderBySelectorElement { - abiEncoder: AbiEncoder.Method; - contractName?: string; - contractAddress?: string; - networkId?: number; -} - -interface TransactionDecoderInfo { - abiEncoder: AbiEncoder.Method; - contractName?: string; - contractAddress?: string; - networkId?: number; -} - interface TransactionProperties { contractName?: string; contractAddress?: string; networkId?: number; } -interface AbiEncoderByNeworkId { - [index: string]: AbiEncoderBySelectorElement; -} - -interface AbiEncoderBySelector { - [index: string]: AbiEncoderByNeworkId; -} - interface DeployedContractInfo { - contractAddress?: string; - networkId?: number; + contractAddress: string; + networkId: number; } interface DeployedContractInfoByName { [index: string]: DeployedContractInfo[]; } -interface TransactionDecodersBySelector { - [index: string]: TransactionDecoderInfo[]; +export class TransactionDecoder { + private _functionInfoBySelector: FunctionInfoBySelector = {}; + + private static getFunctionSelector(calldata: string): string { + if (!calldata.startsWith('0x') || calldata.length < 10) { + throw new Error(`Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`); + } + const functionSelector = calldata.substr(0, 10); + return functionSelector; + } + + public addABI(abiArray: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[]): void { + if (_.isEmpty(abiArray)) { + return; + } + const functionAbis = _.filter(abiArray, abiEntry => { + return abiEntry.type === 'function'; + }) as MethodAbi[]; + _.each(functionAbis, functionAbi => { + const abiEncoder = new AbiEncoder.Method(functionAbi); + const functionSelector = abiEncoder.getSelector(); + if (!(functionSelector in this._functionInfoBySelector)) { + this._functionInfoBySelector[functionSelector] = []; + } + // Recored deployed versions of this decoder + const functionSignature = abiEncoder.getSignature(); + _.each(deploymentInfos, deploymentInfo => { + this._functionInfoBySelector[functionSelector].push({ + functionSignature, + abiEncoder, + contractName, + contractAddress: deploymentInfo.contractAddress, + networkId: deploymentInfo.networkId, + }); + }); + // If there isn't a deployed version of this contract, record it without address/network id + if (_.isEmpty(deploymentInfos)) { + this._functionInfoBySelector[functionSelector].push({ + functionSignature, + abiEncoder, + contractName, + }); + } + }); + } + + public decode(calldata: string, txProperties_?: TransactionProperties): DecodedCalldata { + const functionSelector = TransactionDecoder.getFunctionSelector(calldata); + const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; + + const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; + if (_.isUndefined(candidateFunctionInfos)) { + throw new Error(`No functions registered for selector '${functionSelector}'`); + } + const functionInfo = _.find(candidateFunctionInfos, (txDecoder) => { + return (_.isUndefined(txProperties.contractName) || _.toLower(txDecoder.contractName) === _.toLower(txProperties.contractName)) && + (_.isUndefined(txProperties.contractAddress) || txDecoder.contractAddress === txProperties.contractAddress) && + (_.isUndefined(txProperties.networkId) || txDecoder.networkId === txProperties.networkId); + }); + if (_.isUndefined(functionInfo)) { + throw new Error(`No function registered with properties: ${JSON.stringify(txProperties)}.`); + } else if (_.isUndefined(functionInfo.abiEncoder)) { + throw new Error(`Function ABI Encoder is not defined, for function with properties: ${JSON.stringify(txProperties)}.`); + } + const functionName = functionInfo.abiEncoder.getDataItem().name; + const functionSignature = functionInfo.abiEncoder.getSignatureType(); + const functionArguments = functionInfo.abiEncoder.decode(calldata); + const decodedCalldata = { + functionName, + functionSignature, + functionArguments + } + return decodedCalldata; + } } -export class CalldataDecoder { +export class ZeroExTransactionDecoder extends TransactionDecoder { private readonly _deployedContractInfoByName = {} as DeployedContractInfoByName; - private readonly _abiEncoderBySelector: AbiEncoderBySelector = {}; - private readonly _txDecoders: TransactionDecodersBySelector = {}; - private static _instance: CalldataDecoder; + private static _instance: ZeroExTransactionDecoder; - public static getInstance(): CalldataDecoder { - if (!CalldataDecoder._instance) { - CalldataDecoder._instance = new CalldataDecoder(); + private static getInstance(): ZeroExTransactionDecoder { + if (!ZeroExTransactionDecoder._instance) { + ZeroExTransactionDecoder._instance = new ZeroExTransactionDecoder(); } - return CalldataDecoder._instance; + return ZeroExTransactionDecoder._instance; } private constructor() { + super(); // Load addresses by contract name _.each(NetworkId, (networkId: any) => { if (typeof networkId !== 'number') return; @@ -87,66 +148,18 @@ export class CalldataDecoder { const contractName = conractArtifact.contractName; const contractNameLowercase = _.toLower(contractName); const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; - const functionAbis = _.filter(contractAbi, (abiEntry) => {return abiEntry.type === 'function'}) as MethodAbi[]; - _.each(functionAbis, (functionAbi) => { - const abiEncoder = new AbiEncoder.Method(functionAbi); - const functionSelector = abiEncoder.getSelector(); - if (_.has(this._abiEncoderBySelector, functionSelector)) { - return; - } - if (!(functionSelector in this._txDecoders)) this._txDecoders[functionSelector] = []; - // Recored deployed versions of this decoder - _.each(this._deployedContractInfoByName[contractNameLowercase], (deployedContract) => { - this._txDecoders[functionSelector].push({ - abiEncoder, - contractName, - contractAddress: deployedContract.contractAddress, - networkId: deployedContract.networkId, - }); - }); - // If there isn't a deployed version of this contract, record it without address/network id - if (_.isUndefined(this._deployedContractInfoByName[contractNameLowercase])) { - this._txDecoders[functionSelector].push({ - abiEncoder, - contractName, - }); - } - }); + this.addABI(contractAbi, contractName, this._deployedContractInfoByName[contractNameLowercase]); }); } - private static getFunctionSelector(calldata: string): string { - if (!calldata.startsWith('0x') || calldata.length < 10) { - throw new Error(`Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`); - } - const functionSelector = calldata.substr(0, 10); - return functionSelector; + public static addABI(abiArray: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[]): void { + const instance = ZeroExTransactionDecoder.getInstance(); + instance.addABI(abiArray, contractName, deploymentInfos); } - public static decode(calldata: string, txProperties_?: TransactionProperties): DecodedCalldata { - const functionSelector = CalldataDecoder.getFunctionSelector(calldata); - const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; - const instance = CalldataDecoder.getInstance(); - const txDecodersByFunctionSelector = instance._txDecoders[functionSelector]; - if (_.isUndefined(txDecodersByFunctionSelector)) { - throw new Error(`No decoder registered for function selector '${functionSelector}'`); - } - const txDecoderWithProperties = _.find(txDecodersByFunctionSelector, (txDecoder) => { - return (_.isUndefined(txProperties.contractName) || _.toLower(txDecoder.contractName) === _.toLower(txProperties.contractName)) && - (_.isUndefined(txProperties.contractAddress) || txDecoder.contractAddress === txProperties.contractAddress) && - (_.isUndefined(txProperties.networkId) || txDecoder.networkId === txProperties.networkId); - }); - if (_.isUndefined(txDecoderWithProperties)) { - throw new Error(`No decoder registered with properties: ${JSON.stringify(txProperties)}.`); - } - const functionName = txDecoderWithProperties.abiEncoder.getDataItem().name; - const functionSignature = txDecoderWithProperties.abiEncoder.getSignatureType(); - const functionArguments = txDecoderWithProperties.abiEncoder.decode(calldata); - const decodedCalldata = { - functionName, - functionSignature, - functionArguments - } + public static decode(calldata: string, txProperties?: TransactionProperties): DecodedCalldata { + const instance = ZeroExTransactionDecoder.getInstance(); + const decodedCalldata = instance.decode(calldata, txProperties); return decodedCalldata; } -} \ No newline at end of file +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 3e5058edc3..de32557fc7 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -11,4 +11,4 @@ export { errorUtils } from './error_utils'; export { fetchAsync } from './fetch_async'; export { signTypedDataUtils } from './sign_typed_data_utils'; export import AbiEncoder = require('./abi_encoder'); -export { CalldataDecoder } from './calldata_decoder'; +export { ZeroExTransactionDecoder } from './calldata_decoder'; diff --git a/packages/utils/test/calldata_decoder_test.ts b/packages/utils/test/calldata_decoder_test.ts index 7d5cc9fd92..a7eafed702 100644 --- a/packages/utils/test/calldata_decoder_test.ts +++ b/packages/utils/test/calldata_decoder_test.ts @@ -1,7 +1,7 @@ import * as chai from 'chai'; import 'mocha'; -import { CalldataDecoder } from '../src'; +import { ZeroExTransactionDecoder } from '../src'; import { chaiSetup } from './utils/chai_setup'; chaiSetup.configure(); @@ -13,7 +13,7 @@ describe.only('CalldataDecoder', () => { //const cancelCalldata = '0xd46b02c3000000000000000000000000000000000000000000000000000000000000002000000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a258b39954cef5cb142fd567a46cddb31a6701240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071d75ab9b9204fffc40000000000000000000000000000000000000000000000011c6e19c53d35b66200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c50f2ed000000000000000000000000000000000000000000000000000001689c2bc812000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000'; //const marketBuycalldata = '0xe5fa431b0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008c26348f63f9e008f0dd09a0ce1ed7caf6c1366b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e150a33ffa97a8d22f59c77ae5487b089ef62e90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000001323e717ba3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ea9bd19a0c4b5533ac98f58db0558a96e15ec5f71d64b6070cea4b5df10b7fb35424035000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000006cb262679c522c4f0834041a6248e8feb35f0337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000421c750cedbf0eef0914c09b296f08462c363527f454bcf2dfaaf2f772e290d0ee5b0417d8b95837cbe501494195edc2a5a48c664d2ef74a340e40213c05db8767fa03000000000000000000000000000000000000000000000000000000000000'; const calldata = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; - const decodedCalldata = CalldataDecoder.decode(calldata, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + const decodedCalldata = ZeroExTransactionDecoder.decode(calldata, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); console.log(JSON.stringify(decodedCalldata, null, 4)); expect(5).to.be.equal(5); }); From 896874fb99b47cc256489e6f7be348b2140e6036 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 31 Jan 2019 11:40:33 -0800 Subject: [PATCH 18/39] separated tx decode classes and types into separate files --- packages/utils/src/index.ts | 4 +- ...data_decoder.ts => transaction_decoder.ts} | 91 +------------------ packages/utils/src/types.ts | 34 +++++++ .../utils/src/zeroex_transaction_decoder.ts | 55 +++++++++++ ...er_test.ts => transaction_decoder_test.ts} | 11 +-- 5 files changed, 100 insertions(+), 95 deletions(-) rename packages/utils/src/{calldata_decoder.ts => transaction_decoder.ts} (52%) create mode 100644 packages/utils/src/types.ts create mode 100644 packages/utils/src/zeroex_transaction_decoder.ts rename packages/utils/test/{calldata_decoder_test.ts => transaction_decoder_test.ts} (93%) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index de32557fc7..c0f15f2ab6 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -11,4 +11,6 @@ export { errorUtils } from './error_utils'; export { fetchAsync } from './fetch_async'; export { signTypedDataUtils } from './sign_typed_data_utils'; export import AbiEncoder = require('./abi_encoder'); -export { ZeroExTransactionDecoder } from './calldata_decoder'; +export * from './types'; +export { TransactionDecoder } from './transaction_decoder'; +export { ZeroExTransactionDecoder } from './zeroex_transaction_decoder'; diff --git a/packages/utils/src/calldata_decoder.ts b/packages/utils/src/transaction_decoder.ts similarity index 52% rename from packages/utils/src/calldata_decoder.ts rename to packages/utils/src/transaction_decoder.ts index 36016c7bc6..85d92d553c 100644 --- a/packages/utils/src/calldata_decoder.ts +++ b/packages/utils/src/transaction_decoder.ts @@ -1,44 +1,7 @@ -// Decodes any 0x transaction - -import * as ContractArtifacts from '@0x/contract-artifacts'; -import { SimpleContractArtifact } from '@0x/types'; -import { AbiDefinition, ContractAbi, MethodAbi } from 'ethereum-types'; +import { AbiDefinition, MethodAbi } from 'ethereum-types'; import * as _ from 'lodash'; import { AbiEncoder } from '.'; -import { getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses'; - -export interface FunctionInfo { - functionSignature: string; - contractName?: string; - contractAddress?: string; - networkId?: number; - abiEncoder?: AbiEncoder.Method; -} - -interface FunctionInfoBySelector { - [index: string]: FunctionInfo[]; -} - -export interface DecodedCalldata { - functionName: string; - functionSignature: string; - functionArguments: any; -} - -interface TransactionProperties { - contractName?: string; - contractAddress?: string; - networkId?: number; -} - -interface DeployedContractInfo { - contractAddress: string; - networkId: number; -} - -interface DeployedContractInfoByName { - [index: string]: DeployedContractInfo[]; -} +import { FunctionInfoBySelector, TransactionData, TransactionProperties, DeployedContractInfo } from './types'; export class TransactionDecoder { private _functionInfoBySelector: FunctionInfoBySelector = {}; @@ -86,10 +49,9 @@ export class TransactionDecoder { }); } - public decode(calldata: string, txProperties_?: TransactionProperties): DecodedCalldata { + public decode(calldata: string, txProperties_?: TransactionProperties): TransactionData { const functionSelector = TransactionDecoder.getFunctionSelector(calldata); const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; - const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; if (_.isUndefined(candidateFunctionInfos)) { throw new Error(`No functions registered for selector '${functionSelector}'`); @@ -116,50 +78,3 @@ export class TransactionDecoder { } } -export class ZeroExTransactionDecoder extends TransactionDecoder { - private readonly _deployedContractInfoByName = {} as DeployedContractInfoByName; - private static _instance: ZeroExTransactionDecoder; - - private static getInstance(): ZeroExTransactionDecoder { - if (!ZeroExTransactionDecoder._instance) { - ZeroExTransactionDecoder._instance = new ZeroExTransactionDecoder(); - } - return ZeroExTransactionDecoder._instance; - } - - private constructor() { - super(); - // Load addresses by contract name - _.each(NetworkId, (networkId: any) => { - if (typeof networkId !== 'number') return; - const networkIdAsNumber = networkId as number; - const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkIdAsNumber); - _.each(contractAddressesForNetwork, (contractAddress: string, contractName: string) => { - const contractNameLowercase = _.toLower(contractName); - if (_.isUndefined(this._deployedContractInfoByName[contractNameLowercase])) { - this._deployedContractInfoByName[contractNameLowercase] = []; - } - this._deployedContractInfoByName[contractNameLowercase].push({contractAddress, networkId: networkIdAsNumber}); - }); - }); - // Load contract artifacts - _.each(ContractArtifacts, (contractArtifactAsJson: any) => { - const conractArtifact = contractArtifactAsJson as SimpleContractArtifact; - const contractName = conractArtifact.contractName; - const contractNameLowercase = _.toLower(contractName); - const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; - this.addABI(contractAbi, contractName, this._deployedContractInfoByName[contractNameLowercase]); - }); - } - - public static addABI(abiArray: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[]): void { - const instance = ZeroExTransactionDecoder.getInstance(); - instance.addABI(abiArray, contractName, deploymentInfos); - } - - public static decode(calldata: string, txProperties?: TransactionProperties): DecodedCalldata { - const instance = ZeroExTransactionDecoder.getInstance(); - const decodedCalldata = instance.decode(calldata, txProperties); - return decodedCalldata; - } -} diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts new file mode 100644 index 0000000000..2510a9ec21 --- /dev/null +++ b/packages/utils/src/types.ts @@ -0,0 +1,34 @@ +import { AbiEncoder } from '.'; + +export interface FunctionInfo { + functionSignature: string; + contractName?: string; + contractAddress?: string; + networkId?: number; + abiEncoder?: AbiEncoder.Method; +} + +export interface FunctionInfoBySelector { + [index: string]: FunctionInfo[]; +} + +export interface TransactionData { + functionName: string; + functionSignature: string; + functionArguments: any; +} + +export interface TransactionProperties { + contractName?: string; + contractAddress?: string; + networkId?: number; +} + +export interface DeployedContractInfo { + contractAddress: string; + networkId: number; +} + +export interface DeployedContractInfoByName { + [index: string]: DeployedContractInfo[]; +} diff --git a/packages/utils/src/zeroex_transaction_decoder.ts b/packages/utils/src/zeroex_transaction_decoder.ts new file mode 100644 index 0000000000..049596770c --- /dev/null +++ b/packages/utils/src/zeroex_transaction_decoder.ts @@ -0,0 +1,55 @@ +import { TransactionDecoder } from './transaction_decoder'; +import { getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses'; +import * as ContractArtifacts from '@0x/contract-artifacts'; +import { SimpleContractArtifact } from '@0x/types'; +import { AbiDefinition, ContractAbi } from 'ethereum-types'; +import { TransactionData, DeployedContractInfo, DeployedContractInfoByName, TransactionProperties } from './types'; +import * as _ from 'lodash'; + +export class ZeroExTransactionDecoder extends TransactionDecoder { + private readonly _deployedContractInfoByName = {} as DeployedContractInfoByName; + private static _instance: ZeroExTransactionDecoder; + + private static getInstance(): ZeroExTransactionDecoder { + if (!ZeroExTransactionDecoder._instance) { + ZeroExTransactionDecoder._instance = new ZeroExTransactionDecoder(); + } + return ZeroExTransactionDecoder._instance; + } + + private constructor() { + super(); + // Load addresses by contract name + _.each(NetworkId, (networkId: any) => { + if (typeof networkId !== 'number') return; + const networkIdAsNumber = networkId as number; + const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkIdAsNumber); + _.each(contractAddressesForNetwork, (contractAddress: string, contractName: string) => { + const contractNameLowercase = _.toLower(contractName); + if (_.isUndefined(this._deployedContractInfoByName[contractNameLowercase])) { + this._deployedContractInfoByName[contractNameLowercase] = []; + } + this._deployedContractInfoByName[contractNameLowercase].push({contractAddress, networkId: networkIdAsNumber}); + }); + }); + // Load contract artifacts + _.each(ContractArtifacts, (contractArtifactAsJson: any) => { + const conractArtifact = contractArtifactAsJson as SimpleContractArtifact; + const contractName = conractArtifact.contractName; + const contractNameLowercase = _.toLower(contractName); + const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; + this.addABI(contractAbi, contractName, this._deployedContractInfoByName[contractNameLowercase]); + }); + } + + public static addABI(abiArray: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[]): void { + const instance = ZeroExTransactionDecoder.getInstance(); + instance.addABI(abiArray, contractName, deploymentInfos); + } + + public static decode(calldata: string, txProperties?: TransactionProperties): TransactionData { + const instance = ZeroExTransactionDecoder.getInstance(); + const decodedCalldata = instance.decode(calldata, txProperties); + return decodedCalldata; + } +} \ No newline at end of file diff --git a/packages/utils/test/calldata_decoder_test.ts b/packages/utils/test/transaction_decoder_test.ts similarity index 93% rename from packages/utils/test/calldata_decoder_test.ts rename to packages/utils/test/transaction_decoder_test.ts index a7eafed702..b360876b46 100644 --- a/packages/utils/test/calldata_decoder_test.ts +++ b/packages/utils/test/transaction_decoder_test.ts @@ -7,15 +7,14 @@ import { chaiSetup } from './utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -describe.only('CalldataDecoder', () => { - describe.only('decodeCalldata', () => { - it.only('should successfull decode fillOrder calldata', async () => { +describe.only('TransactionDecoder', () => { + describe('decode', () => { + it('should successfull decode fillOrder calldata', async () => { //const cancelCalldata = '0xd46b02c3000000000000000000000000000000000000000000000000000000000000002000000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a258b39954cef5cb142fd567a46cddb31a6701240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071d75ab9b9204fffc40000000000000000000000000000000000000000000000011c6e19c53d35b66200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c50f2ed000000000000000000000000000000000000000000000000000001689c2bc812000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000'; //const marketBuycalldata = '0xe5fa431b0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008c26348f63f9e008f0dd09a0ce1ed7caf6c1366b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e150a33ffa97a8d22f59c77ae5487b089ef62e90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000001323e717ba3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ea9bd19a0c4b5533ac98f58db0558a96e15ec5f71d64b6070cea4b5df10b7fb35424035000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000006cb262679c522c4f0834041a6248e8feb35f0337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000421c750cedbf0eef0914c09b296f08462c363527f454bcf2dfaaf2f772e290d0ee5b0417d8b95837cbe501494195edc2a5a48c664d2ef74a340e40213c05db8767fa03000000000000000000000000000000000000000000000000000000000000'; const calldata = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; - const decodedCalldata = ZeroExTransactionDecoder.decode(calldata, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); - console.log(JSON.stringify(decodedCalldata, null, 4)); - expect(5).to.be.equal(5); + const decodedTxData = ZeroExTransactionDecoder.decode(calldata, {contractName: "Dutchauction"});//{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + console.log(decodedTxData); }); }); }); From 436d87da98a2025106bfb42838bd18054f7aba63 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 31 Jan 2019 13:20:18 -0800 Subject: [PATCH 19/39] Ran prettier and linter --- packages/utils/src/transaction_decoder.ts | 48 +++++++++------- .../utils/src/zeroex_transaction_decoder.ts | 55 +++++++++++-------- .../utils/test/transaction_decoder_test.ts | 5 +- 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/packages/utils/src/transaction_decoder.ts b/packages/utils/src/transaction_decoder.ts index 85d92d553c..35a889a4e1 100644 --- a/packages/utils/src/transaction_decoder.ts +++ b/packages/utils/src/transaction_decoder.ts @@ -1,26 +1,27 @@ import { AbiDefinition, MethodAbi } from 'ethereum-types'; import * as _ from 'lodash'; + import { AbiEncoder } from '.'; -import { FunctionInfoBySelector, TransactionData, TransactionProperties, DeployedContractInfo } from './types'; +import { DeployedContractInfo, FunctionInfoBySelector, TransactionData, TransactionProperties } from './types'; export class TransactionDecoder { - private _functionInfoBySelector: FunctionInfoBySelector = {}; - - private static getFunctionSelector(calldata: string): string { - if (!calldata.startsWith('0x') || calldata.length < 10) { - throw new Error(`Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`); + private readonly _functionInfoBySelector: FunctionInfoBySelector = {}; + + private static _getFunctionSelector(calldata: string): string { + const functionSelectorLength = 10; + if (!calldata.startsWith('0x') || calldata.length < functionSelectorLength) { + throw new Error( + `Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`, + ); } - const functionSelector = calldata.substr(0, 10); + const functionSelector = calldata.substr(0, functionSelectorLength); return functionSelector; } public addABI(abiArray: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[]): void { - if (_.isEmpty(abiArray)) { - return; - } - const functionAbis = _.filter(abiArray, abiEntry => { + const functionAbis: MethodAbi[] = _.filter(abiArray, abiEntry => { return abiEntry.type === 'function'; - }) as MethodAbi[]; + }); _.each(functionAbis, functionAbi => { const abiEncoder = new AbiEncoder.Method(functionAbi); const functionSelector = abiEncoder.getSelector(); @@ -50,21 +51,27 @@ export class TransactionDecoder { } public decode(calldata: string, txProperties_?: TransactionProperties): TransactionData { - const functionSelector = TransactionDecoder.getFunctionSelector(calldata); + const functionSelector = TransactionDecoder._getFunctionSelector(calldata); const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; if (_.isUndefined(candidateFunctionInfos)) { throw new Error(`No functions registered for selector '${functionSelector}'`); } - const functionInfo = _.find(candidateFunctionInfos, (txDecoder) => { - return (_.isUndefined(txProperties.contractName) || _.toLower(txDecoder.contractName) === _.toLower(txProperties.contractName)) && - (_.isUndefined(txProperties.contractAddress) || txDecoder.contractAddress === txProperties.contractAddress) && - (_.isUndefined(txProperties.networkId) || txDecoder.networkId === txProperties.networkId); + const functionInfo = _.find(candidateFunctionInfos, txDecoder => { + return ( + (_.isUndefined(txProperties.contractName) || + _.toLower(txDecoder.contractName) === _.toLower(txProperties.contractName)) && + (_.isUndefined(txProperties.contractAddress) || + txDecoder.contractAddress === txProperties.contractAddress) && + (_.isUndefined(txProperties.networkId) || txDecoder.networkId === txProperties.networkId) + ); }); if (_.isUndefined(functionInfo)) { throw new Error(`No function registered with properties: ${JSON.stringify(txProperties)}.`); } else if (_.isUndefined(functionInfo.abiEncoder)) { - throw new Error(`Function ABI Encoder is not defined, for function with properties: ${JSON.stringify(txProperties)}.`); + throw new Error( + `Function ABI Encoder is not defined, for function with properties: ${JSON.stringify(txProperties)}.`, + ); } const functionName = functionInfo.abiEncoder.getDataItem().name; const functionSignature = functionInfo.abiEncoder.getSignatureType(); @@ -72,9 +79,8 @@ export class TransactionDecoder { const decodedCalldata = { functionName, functionSignature, - functionArguments - } + functionArguments, + }; return decodedCalldata; } } - diff --git a/packages/utils/src/zeroex_transaction_decoder.ts b/packages/utils/src/zeroex_transaction_decoder.ts index 049596770c..f236257cb5 100644 --- a/packages/utils/src/zeroex_transaction_decoder.ts +++ b/packages/utils/src/zeroex_transaction_decoder.ts @@ -1,16 +1,31 @@ -import { TransactionDecoder } from './transaction_decoder'; import { getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses'; import * as ContractArtifacts from '@0x/contract-artifacts'; import { SimpleContractArtifact } from '@0x/types'; import { AbiDefinition, ContractAbi } from 'ethereum-types'; -import { TransactionData, DeployedContractInfo, DeployedContractInfoByName, TransactionProperties } from './types'; import * as _ from 'lodash'; +import { TransactionDecoder } from './transaction_decoder'; +import { DeployedContractInfo, DeployedContractInfoByName, TransactionData, TransactionProperties } from './types'; + export class ZeroExTransactionDecoder extends TransactionDecoder { - private readonly _deployedContractInfoByName = {} as DeployedContractInfoByName; private static _instance: ZeroExTransactionDecoder; - private static getInstance(): ZeroExTransactionDecoder { + public static addABI( + abiArray: AbiDefinition[], + contractName: string, + deploymentInfos?: DeployedContractInfo[], + ): void { + const instance = ZeroExTransactionDecoder._getInstance(); + instance.addABI(abiArray, contractName, deploymentInfos); + } + + public static decode(calldata: string, txProperties?: TransactionProperties): TransactionData { + const instance = ZeroExTransactionDecoder._getInstance(); + const decodedCalldata = instance.decode(calldata, txProperties); + return decodedCalldata; + } + + private static _getInstance(): ZeroExTransactionDecoder { if (!ZeroExTransactionDecoder._instance) { ZeroExTransactionDecoder._instance = new ZeroExTransactionDecoder(); } @@ -20,16 +35,21 @@ export class ZeroExTransactionDecoder extends TransactionDecoder { private constructor() { super(); // Load addresses by contract name + const deployedContractInfoByName: DeployedContractInfoByName = {}; _.each(NetworkId, (networkId: any) => { - if (typeof networkId !== 'number') return; - const networkIdAsNumber = networkId as number; - const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkIdAsNumber); + if (typeof networkId !== 'number') { + return; + } + const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkId); _.each(contractAddressesForNetwork, (contractAddress: string, contractName: string) => { const contractNameLowercase = _.toLower(contractName); - if (_.isUndefined(this._deployedContractInfoByName[contractNameLowercase])) { - this._deployedContractInfoByName[contractNameLowercase] = []; + if (_.isUndefined(deployedContractInfoByName[contractNameLowercase])) { + deployedContractInfoByName[contractNameLowercase] = []; } - this._deployedContractInfoByName[contractNameLowercase].push({contractAddress, networkId: networkIdAsNumber}); + deployedContractInfoByName[contractNameLowercase].push({ + contractAddress, + networkId, + }); }); }); // Load contract artifacts @@ -38,18 +58,7 @@ export class ZeroExTransactionDecoder extends TransactionDecoder { const contractName = conractArtifact.contractName; const contractNameLowercase = _.toLower(contractName); const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; - this.addABI(contractAbi, contractName, this._deployedContractInfoByName[contractNameLowercase]); + this.addABI(contractAbi, contractName, deployedContractInfoByName[contractNameLowercase]); }); } - - public static addABI(abiArray: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[]): void { - const instance = ZeroExTransactionDecoder.getInstance(); - instance.addABI(abiArray, contractName, deploymentInfos); - } - - public static decode(calldata: string, txProperties?: TransactionProperties): TransactionData { - const instance = ZeroExTransactionDecoder.getInstance(); - const decodedCalldata = instance.decode(calldata, txProperties); - return decodedCalldata; - } -} \ No newline at end of file +} diff --git a/packages/utils/test/transaction_decoder_test.ts b/packages/utils/test/transaction_decoder_test.ts index b360876b46..eee712e984 100644 --- a/packages/utils/test/transaction_decoder_test.ts +++ b/packages/utils/test/transaction_decoder_test.ts @@ -12,8 +12,9 @@ describe.only('TransactionDecoder', () => { it('should successfull decode fillOrder calldata', async () => { //const cancelCalldata = '0xd46b02c3000000000000000000000000000000000000000000000000000000000000002000000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a258b39954cef5cb142fd567a46cddb31a6701240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071d75ab9b9204fffc40000000000000000000000000000000000000000000000011c6e19c53d35b66200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c50f2ed000000000000000000000000000000000000000000000000000001689c2bc812000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000'; //const marketBuycalldata = '0xe5fa431b0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008c26348f63f9e008f0dd09a0ce1ed7caf6c1366b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e150a33ffa97a8d22f59c77ae5487b089ef62e90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000001323e717ba3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ea9bd19a0c4b5533ac98f58db0558a96e15ec5f71d64b6070cea4b5df10b7fb35424035000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000006cb262679c522c4f0834041a6248e8feb35f0337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000421c750cedbf0eef0914c09b296f08462c363527f454bcf2dfaaf2f772e290d0ee5b0417d8b95837cbe501494195edc2a5a48c664d2ef74a340e40213c05db8767fa03000000000000000000000000000000000000000000000000000000000000'; - const calldata = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; - const decodedTxData = ZeroExTransactionDecoder.decode(calldata, {contractName: "Dutchauction"});//{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + const calldata = + '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; + const decodedTxData = ZeroExTransactionDecoder.decode(calldata, { contractName: 'Dutchauction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); console.log(decodedTxData); }); }); From f7b58e7f64dc5af1e4ac8e7159717c78f0767c85 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 31 Jan 2019 13:38:49 -0800 Subject: [PATCH 20/39] moved ZeroExTransactionDecoder into contract wrappers --- .../src/utils}/zeroex_transaction_decoder.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename packages/{utils/src => contract-wrappers/src/utils}/zeroex_transaction_decoder.ts (96%) diff --git a/packages/utils/src/zeroex_transaction_decoder.ts b/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts similarity index 96% rename from packages/utils/src/zeroex_transaction_decoder.ts rename to packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts index f236257cb5..441424e92e 100644 --- a/packages/utils/src/zeroex_transaction_decoder.ts +++ b/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts @@ -4,8 +4,7 @@ import { SimpleContractArtifact } from '@0x/types'; import { AbiDefinition, ContractAbi } from 'ethereum-types'; import * as _ from 'lodash'; -import { TransactionDecoder } from './transaction_decoder'; -import { DeployedContractInfo, DeployedContractInfoByName, TransactionData, TransactionProperties } from './types'; +import { DeployedContractInfo, DeployedContractInfoByName, TransactionData, TransactionDecoder, TransactionProperties } from '@0x/utils'; export class ZeroExTransactionDecoder extends TransactionDecoder { private static _instance: ZeroExTransactionDecoder; From 171618d32b649b976f8ecffa69cff3ef30fc7c7d Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 31 Jan 2019 14:07:09 -0800 Subject: [PATCH 21/39] Added comments for transaction decoder --- packages/contract-wrappers/src/index.ts | 1 + .../src/utils/zeroex_transaction_decoder.ts | 31 ++++++++++--- packages/utils/src/transaction_decoder.ts | 46 +++++++++++++------ 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 69bbe3c91b..2693668960 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -37,6 +37,7 @@ export { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapp export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper'; export { TransactionEncoder } from './utils/transaction_encoder'; +export { ZeroExTransactionDecoder } from './utils/zeroex_transaction_decoder'; export { ContractWrappersError, diff --git a/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts b/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts index 441424e92e..4a5a5809f5 100644 --- a/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts +++ b/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts @@ -8,29 +8,48 @@ import { DeployedContractInfo, DeployedContractInfoByName, TransactionData, Tran export class ZeroExTransactionDecoder extends TransactionDecoder { private static _instance: ZeroExTransactionDecoder; - + /** + * Adds a set of ABI definitions, after which transaction data targeting these ABI's can be decoded. + * Additional properties can be included to disambiguate similar ABI's. For example, if two functions + * have the same signature but different parameter names, then their ABI definitions can be disambiguated + * by specifying a contract name. + * @param abiDefinitions ABI definitions for a given contract. + * @param contractName Name of contract that encapsulates the ABI definitions (optional). + * @param deploymentInfos A collection of network/address pairs where this contract is deployed (optional). + */ public static addABI( - abiArray: AbiDefinition[], + abiDefinitions: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[], ): void { const instance = ZeroExTransactionDecoder._getInstance(); - instance.addABI(abiArray, contractName, deploymentInfos); + instance.addABI(abiDefinitions, contractName, deploymentInfos); } - + /** + * Decodes transaction data for a known ABI. + * @param txData hex-encoded transaction data. + * @param txProperties Properties about the transaction used to disambiguate similar ABI's (optional). + * @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments. + */ public static decode(calldata: string, txProperties?: TransactionProperties): TransactionData { const instance = ZeroExTransactionDecoder._getInstance(); const decodedCalldata = instance.decode(calldata, txProperties); return decodedCalldata; } - + /** + * Gets instance for singleton. + * @return singleton instance. + */ private static _getInstance(): ZeroExTransactionDecoder { if (!ZeroExTransactionDecoder._instance) { ZeroExTransactionDecoder._instance = new ZeroExTransactionDecoder(); } return ZeroExTransactionDecoder._instance; } - + /** + * Adds all known contract ABI's defined by the @0x/Artifacts package, along with known 0x + * contract addresses. + */ private constructor() { super(); // Load addresses by contract name diff --git a/packages/utils/src/transaction_decoder.ts b/packages/utils/src/transaction_decoder.ts index 35a889a4e1..1ce2ea3b0e 100644 --- a/packages/utils/src/transaction_decoder.ts +++ b/packages/utils/src/transaction_decoder.ts @@ -6,29 +6,43 @@ import { DeployedContractInfo, FunctionInfoBySelector, TransactionData, Transact export class TransactionDecoder { private readonly _functionInfoBySelector: FunctionInfoBySelector = {}; - - private static _getFunctionSelector(calldata: string): string { + /** + * Retrieves the function selector from tranasction data. + * @param txData hex-encoded transaction data. + * @return hex-encoded function selector. + */ + private static _getFunctionSelector(txData: string): string { const functionSelectorLength = 10; - if (!calldata.startsWith('0x') || calldata.length < functionSelectorLength) { + if (!txData.startsWith('0x') || txData.length < functionSelectorLength) { throw new Error( - `Malformed calldata. Must include hex prefix '0x' and 4-byte function selector. Got '${calldata}'`, + `Malformed transaction data. Must include a hex prefix '0x' and 4-byte function selector. Got '${txData}'`, ); } const functionSelector = calldata.substr(0, functionSelectorLength); return functionSelector; } - - public addABI(abiArray: AbiDefinition[], contractName: string, deploymentInfos?: DeployedContractInfo[]): void { - const functionAbis: MethodAbi[] = _.filter(abiArray, abiEntry => { + /** + * Adds a set of ABI definitions, after which transaction data targeting these ABI's can be decoded. + * Additional properties can be included to disambiguate similar ABI's. For example, if two functions + * have the same signature but different parameter names, then their ABI definitions can be disambiguated + * by specifying a contract name. + * @param abiDefinitions ABI definitions for a given contract. + * @param contractName Name of contract that encapsulates the ABI definitions (optional). + * @param deploymentInfos A collection of network/address pairs where this contract is deployed (optional). + */ + public addABI(abiDefinitions: AbiDefinition[], contractName?: string, deploymentInfos?: DeployedContractInfo[]): void { + // Disregard definitions that are not functions + const functionAbis: MethodAbi[] = _.filter(abiDefinitions, abiEntry => { return abiEntry.type === 'function'; }); + // Record function ABI's _.each(functionAbis, functionAbi => { const abiEncoder = new AbiEncoder.Method(functionAbi); const functionSelector = abiEncoder.getSelector(); if (!(functionSelector in this._functionInfoBySelector)) { this._functionInfoBySelector[functionSelector] = []; } - // Recored deployed versions of this decoder + // Recored a copy of this ABI for each deployment const functionSignature = abiEncoder.getSignature(); _.each(deploymentInfos, deploymentInfo => { this._functionInfoBySelector[functionSelector].push({ @@ -39,7 +53,7 @@ export class TransactionDecoder { networkId: deploymentInfo.networkId, }); }); - // If there isn't a deployed version of this contract, record it without address/network id + // There is no deployment info for this contract; record it without an address/network id if (_.isEmpty(deploymentInfos)) { this._functionInfoBySelector[functionSelector].push({ functionSignature, @@ -49,9 +63,15 @@ export class TransactionDecoder { } }); } - - public decode(calldata: string, txProperties_?: TransactionProperties): TransactionData { - const functionSelector = TransactionDecoder._getFunctionSelector(calldata); + /** + * Decodes transaction data for a known ABI. + * @param txData hex-encoded transaction data. + * @param txProperties Properties about the transaction used to disambiguate similar ABI's (optional). + * @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments. + */ + public decode(txData: string, txProperties_?: TransactionProperties): TransactionData { + // Lookup + const functionSelector = TransactionDecoder._getFunctionSelector(txData); const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; if (_.isUndefined(candidateFunctionInfos)) { @@ -75,7 +95,7 @@ export class TransactionDecoder { } const functionName = functionInfo.abiEncoder.getDataItem().name; const functionSignature = functionInfo.abiEncoder.getSignatureType(); - const functionArguments = functionInfo.abiEncoder.decode(calldata); + const functionArguments = functionInfo.abiEncoder.decode(txData); const decodedCalldata = { functionName, functionSignature, From 63f41df3272060bf44924c586fd882595428eff6 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 31 Jan 2019 14:07:46 -0800 Subject: [PATCH 22/39] started writing tests for zeroex tx decoder --- .../test/zeroex_transaction_decoder_test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts diff --git a/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts b/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts new file mode 100644 index 0000000000..7ac5070763 --- /dev/null +++ b/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts @@ -0,0 +1,20 @@ +import * as chai from 'chai'; +import 'mocha'; + +import { ZeroExTransactionDecoder } from '../src'; +import { chaiSetup } from './utils/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe.only('ZeroExTransactionDecoder', () => { + const sampleMatchOrdersTxData = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; + + describe('decode', () => { + it('should successfully decode matchOrders txData', async () => { + const expected + const decodedTxData = ZeroExTransactionDecoder.decode(calldata, { contractName: 'Dutchauction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + console.log(decodedTxData); + }); + }); +}); From 5a231fb0575a00dfcf1237ec4e733cbeb96e984d Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 31 Jan 2019 17:55:23 -0800 Subject: [PATCH 23/39] Prep for txData decoder tests --- .../src/utils/transaction_encoder.ts | 17 ++++ .../test/zeroex_transaction_decoder_test.ts | 88 ++++++++++++++++++- packages/utils/src/address_utils.ts | 25 +++++- packages/utils/src/index.ts | 1 - packages/utils/src/transaction_decoder.ts | 6 +- .../utils/test/transaction_decoder_test.ts | 13 +-- 6 files changed, 130 insertions(+), 20 deletions(-) diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts index 307487a9be..5faa593a59 100644 --- a/packages/contract-wrappers/src/utils/transaction_encoder.ts +++ b/packages/contract-wrappers/src/utils/transaction_encoder.ts @@ -241,6 +241,23 @@ export class TransactionEncoder { ); return abiEncodedData; } + /** + * Encodes a matchOrders transaction. + * @param leftOrder + * @param rightOrder + * @return Hex encoded abi of the function call. + */ + public matchOrdersTx(leftOrder: SignedOrder, rightOrder: SignedOrder): string { + assert.doesConformToSchema('order', leftOrder, schemas.orderSchema); + assert.doesConformToSchema('order', rightOrder, schemas.orderSchema); + const abiEncodedData = this._getExchangeContract().matchOrders.getABIEncodedTransactionData( + leftOrder, + rightOrder, + leftOrder.signature, + rightOrder.signature, + ); + return abiEncodedData; + } /** * Encodes a preSign transaction. * @param hash Hash to pre-sign diff --git a/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts b/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts index 7ac5070763..e4fbb8b999 100644 --- a/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts +++ b/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts @@ -1,20 +1,100 @@ +import { assetDataUtils } from '@0x/order-utils'; import * as chai from 'chai'; import 'mocha'; +import * as _ from 'lodash'; +import { addressUtils, BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ZeroExTransactionDecoder } from '../src'; +import { + constants, + OrderFactory, + web3Wrapper, +} from '@0x/contracts-test-utils'; +import { SignedOrder } from '@0x/types'; + +import { TransactionEncoder, ZeroExTransactionDecoder } from '../src'; import { chaiSetup } from './utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; describe.only('ZeroExTransactionDecoder', () => { + let orderFactory: OrderFactory; + let defaultERC20MakerAssetAddress = addressUtils.generatePseudoRandomAddress(); + let defaultERC20TakerAssetAddress = addressUtils.generatePseudoRandomAddress(); + let signedOrderLeft: SignedOrder; + let signedOrderRifght: SignedOrder; + let matchOrdersTxData: string; const sampleMatchOrdersTxData = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; + before(async () => { + // Create accounts + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + + let makerAddressLeft = addressUtils.generatePseudoRandomAddress(); + let makerAddressRight = addressUtils.generatePseudoRandomAddress(); + const exchangeAddress = addressUtils.generatePseudoRandomAddress(); + const feeRecipientAddress = addressUtils.generatePseudoRandomAddress();; + // Create orders to match + const defaultOrderParamsLeft = { + makerAddress: makerAddressLeft, + exchangeAddress, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + feeRecipientAddress, + }; + const defaultOrderParamsRight = { + makerAddress: makerAddressRight, + exchangeAddress, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + feeRecipientAddress, + }; + + const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)]; + const orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft); + const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)]; + const orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight); + + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: new BigNumber(1), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + makerAssetAmount: new BigNumber(1), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18), + }); + + + //matchOrdersTxData = TransactionEncoder.matchOrdersTx(signedOrderLeft, signedOrderRight); + }); + describe('decode', () => { - it('should successfully decode matchOrders txData', async () => { - const expected - const decodedTxData = ZeroExTransactionDecoder.decode(calldata, { contractName: 'Dutchauction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + /* + it('should successfully decode DutchAuction.matchOrders txData', async () => { + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName: 'DutchAuction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); console.log(decodedTxData); }); + it('should successfully decode Exchange.matchOrders txData', async () => { + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName: 'Exchange' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + console.log(decodedTxData); + }); + it('should successfully decode Exchange.matchOrders, using exchange address to identify the exchange contract', async () => { + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + console.log(decodedTxData); + }); + it('should throw if cannot decode txData', async () => { + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + console.log(decodedTxData); + });*/ + }); + + describe('addABI', () => { + /*it('should successfully add a new ABI', async () => { + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName: 'DutchAuction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); + console.log(decodedTxData); + });*/ }); }); diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts index 1fc9604085..318504c37c 100644 --- a/packages/utils/src/address_utils.ts +++ b/packages/utils/src/address_utils.ts @@ -1,10 +1,13 @@ -import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util'; +import { addHexPrefix, stripHexPrefix, sha3 } from 'ethereumjs-util'; import * as jsSHA3 from 'js-sha3'; import * as _ from 'lodash'; +import { BigNumber } from './configured_bignumber'; + const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i; const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/; const ADDRESS_LENGTH = 40; +const MAX_DIGITS_IN_UNSIGNED_256_INT = 78; export const addressUtils = { isChecksumAddress(address: string): boolean { @@ -43,4 +46,24 @@ export const addressUtils = { padZeros(address: string): string { return addHexPrefix(_.padStart(stripHexPrefix(address), ADDRESS_LENGTH, '0')); }, + /** + * Generates a pseudo-random 256-bit salt. + * The salt can be included in a 0x order, ensuring that the order generates a unique orderHash + * and will not collide with other outstanding orders that are identical in all other parameters. + * @return A pseudo-random 256-bit number that can be used as a salt. + */ + generatePseudoRandomSalt(): BigNumber { + // BigNumber.random returns a pseudo-random number between 0 & 1 with a passed in number of decimal places. + // Source: https://mikemcl.github.io/bignumber.js/#random + const randomNumber = BigNumber.random(MAX_DIGITS_IN_UNSIGNED_256_INT); + const factor = new BigNumber(10).pow(MAX_DIGITS_IN_UNSIGNED_256_INT - 1); + const salt = randomNumber.times(factor); + return salt; + }, + generatePseudoRandomAddress(): string { + const randomBigNum = addressUtils.generatePseudoRandomSalt(); + const randomBuff = sha3(randomBigNum.toString()); + const randomAddress = `0x${randomBuff.slice(0, 20).toString('hex')}`; + return randomAddress; + } }; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index c0f15f2ab6..6f1c14c832 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -13,4 +13,3 @@ export { signTypedDataUtils } from './sign_typed_data_utils'; export import AbiEncoder = require('./abi_encoder'); export * from './types'; export { TransactionDecoder } from './transaction_decoder'; -export { ZeroExTransactionDecoder } from './zeroex_transaction_decoder'; diff --git a/packages/utils/src/transaction_decoder.ts b/packages/utils/src/transaction_decoder.ts index 1ce2ea3b0e..2c3b96c72b 100644 --- a/packages/utils/src/transaction_decoder.ts +++ b/packages/utils/src/transaction_decoder.ts @@ -18,7 +18,7 @@ export class TransactionDecoder { `Malformed transaction data. Must include a hex prefix '0x' and 4-byte function selector. Got '${txData}'`, ); } - const functionSelector = calldata.substr(0, functionSelectorLength); + const functionSelector = txData.substr(0, functionSelectorLength); return functionSelector; } /** @@ -32,9 +32,9 @@ export class TransactionDecoder { */ public addABI(abiDefinitions: AbiDefinition[], contractName?: string, deploymentInfos?: DeployedContractInfo[]): void { // Disregard definitions that are not functions - const functionAbis: MethodAbi[] = _.filter(abiDefinitions, abiEntry => { + const functionAbis = _.filter(abiDefinitions, abiEntry => { return abiEntry.type === 'function'; - }); + }) as MethodAbi[]; // Record function ABI's _.each(functionAbis, functionAbi => { const abiEncoder = new AbiEncoder.Method(functionAbi); diff --git a/packages/utils/test/transaction_decoder_test.ts b/packages/utils/test/transaction_decoder_test.ts index eee712e984..f214b17338 100644 --- a/packages/utils/test/transaction_decoder_test.ts +++ b/packages/utils/test/transaction_decoder_test.ts @@ -1,21 +1,12 @@ import * as chai from 'chai'; import 'mocha'; -import { ZeroExTransactionDecoder } from '../src'; + import { chaiSetup } from './utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; describe.only('TransactionDecoder', () => { - describe('decode', () => { - it('should successfull decode fillOrder calldata', async () => { - //const cancelCalldata = '0xd46b02c3000000000000000000000000000000000000000000000000000000000000002000000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a258b39954cef5cb142fd567a46cddb31a6701240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071d75ab9b9204fffc40000000000000000000000000000000000000000000000011c6e19c53d35b66200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c50f2ed000000000000000000000000000000000000000000000000000001689c2bc812000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000'; - //const marketBuycalldata = '0xe5fa431b0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008c26348f63f9e008f0dd09a0ce1ed7caf6c1366b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e150a33ffa97a8d22f59c77ae5487b089ef62e90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000001323e717ba3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ea9bd19a0c4b5533ac98f58db0558a96e15ec5f71d64b6070cea4b5df10b7fb35424035000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000006cb262679c522c4f0834041a6248e8feb35f0337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000421c750cedbf0eef0914c09b296f08462c363527f454bcf2dfaaf2f772e290d0ee5b0417d8b95837cbe501494195edc2a5a48c664d2ef74a340e40213c05db8767fa03000000000000000000000000000000000000000000000000000000000000'; - const calldata = - '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; - const decodedTxData = ZeroExTransactionDecoder.decode(calldata, { contractName: 'Dutchauction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); - console.log(decodedTxData); - }); - }); + }); From d9c4c74a56c913e90f3c76566c64950fec86063b Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 17:02:47 -0800 Subject: [PATCH 24/39] Added tests for ZeroExTransactionDecoder --- .../src/utils/transaction_encoder.ts | 4 +- .../src/utils/zeroex_transaction_decoder.ts | 8 +- .../test/zeroex_transaction_decoder_test.ts | 218 +++++++++++++----- packages/utils/src/address_utils.ts | 2 +- packages/utils/src/transaction_decoder.ts | 8 +- .../utils/test/transaction_decoder_test.ts | 5 +- 6 files changed, 171 insertions(+), 74 deletions(-) diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts index 5faa593a59..8bf67ee56c 100644 --- a/packages/contract-wrappers/src/utils/transaction_encoder.ts +++ b/packages/contract-wrappers/src/utils/transaction_encoder.ts @@ -243,8 +243,8 @@ export class TransactionEncoder { } /** * Encodes a matchOrders transaction. - * @param leftOrder - * @param rightOrder + * @param leftOrder First order to match. + * @param rightOrder Second order to match. * @return Hex encoded abi of the function call. */ public matchOrdersTx(leftOrder: SignedOrder, rightOrder: SignedOrder): string { diff --git a/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts b/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts index 4a5a5809f5..17f06497c4 100644 --- a/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts +++ b/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts @@ -4,7 +4,13 @@ import { SimpleContractArtifact } from '@0x/types'; import { AbiDefinition, ContractAbi } from 'ethereum-types'; import * as _ from 'lodash'; -import { DeployedContractInfo, DeployedContractInfoByName, TransactionData, TransactionDecoder, TransactionProperties } from '@0x/utils'; +import { + DeployedContractInfo, + DeployedContractInfoByName, + TransactionData, + TransactionDecoder, + TransactionProperties, +} from '@0x/utils'; export class ZeroExTransactionDecoder extends TransactionDecoder { private static _instance: ZeroExTransactionDecoder; diff --git a/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts b/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts index e4fbb8b999..83c810c3af 100644 --- a/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts +++ b/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts @@ -1,100 +1,190 @@ +import { constants, OrderFactory } from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; -import * as chai from 'chai'; -import 'mocha'; -import * as _ from 'lodash'; -import { addressUtils, BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -import { - constants, - OrderFactory, - web3Wrapper, -} from '@0x/contracts-test-utils'; import { SignedOrder } from '@0x/types'; +import { AbiEncoder, addressUtils, BigNumber } from '@0x/utils'; +import * as chai from 'chai'; +import { MethodAbi } from 'ethereum-types'; +import * as _ from 'lodash'; +import 'mocha'; + +import { ContractAddresses, ContractWrappers } from '../src'; +import { ZeroExTransactionDecoder } from '../src/utils/zeroex_transaction_decoder'; -import { TransactionEncoder, ZeroExTransactionDecoder } from '../src'; import { chaiSetup } from './utils/chai_setup'; +import { migrateOnceAsync } from './utils/migrate'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + describe.only('ZeroExTransactionDecoder', () => { - let orderFactory: OrderFactory; - let defaultERC20MakerAssetAddress = addressUtils.generatePseudoRandomAddress(); - let defaultERC20TakerAssetAddress = addressUtils.generatePseudoRandomAddress(); + const defaultERC20MakerAssetAddress = addressUtils.generatePseudoRandomAddress(); + const matchOrdersSignature = + 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)'; let signedOrderLeft: SignedOrder; - let signedOrderRifght: SignedOrder; + let signedOrderRight: SignedOrder; + let orderLeft = {}; + let orderRight = {}; let matchOrdersTxData: string; - const sampleMatchOrdersTxData = '0x3c28d861000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000500000000000000000000000000da912ecc847b3d98ca882e396e693e485deed5180000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008bb6a7394e2f000000000000000000000000000000000000000000000000868cab59cce788000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c51035008197e43b4d84439ec534b62670eaaaf4a46f50ff37ff62f6d1c1fbe8b036d3c000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000503f9794d6a6bb0df8fbb19a2b3e2aeab35339ad000000000000000000000000000000000000000000000000000000000000000000000000000000003997d0f55d1daa549e95c240bc6353636f4cf9740000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff20000000000000000000000008124071f810d533ff63de61d0c98db99eeb99d6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000871bcc4c32c9d66800000000000000000000000000000000000000000000000000008a70a4d2d2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c510350c20e53540c9b2c9207ad9a04e472e2224af211f08efc2f0eec15d7e1cfbf2109000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c8f294b2728c269a9d01a1b58fe7cae2ef7895bd2de48cc3101eb47464d96594340924793fc8325db26a3abd5602605806a82ca77e810494c5ecab58b03449de80300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000421c372d6daa8e6ce2c696e51b6e1e33f10fd2b41b403cd88c311a617c3656ea02fe454e51cddf4682751bea9a02ce725cf364d1107f27be427d5157adbdcca2609b03000000000000000000000000000000000000000000000000000000000000'; + let contractAddresses: ContractAddresses; before(async () => { // Create accounts const accounts = await web3Wrapper.getAvailableAddressesAsync(); - - let makerAddressLeft = addressUtils.generatePseudoRandomAddress(); - let makerAddressRight = addressUtils.generatePseudoRandomAddress(); + const [makerAddressLeft, makerAddressRight] = accounts.slice(0, 2); const exchangeAddress = addressUtils.generatePseudoRandomAddress(); - const feeRecipientAddress = addressUtils.generatePseudoRandomAddress();; - // Create orders to match - const defaultOrderParamsLeft = { - makerAddress: makerAddressLeft, - exchangeAddress, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - feeRecipientAddress, - }; - const defaultOrderParamsRight = { - makerAddress: makerAddressRight, - exchangeAddress, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), - feeRecipientAddress, - }; - + const feeRecipientAddress = addressUtils.generatePseudoRandomAddress(); const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)]; - const orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft); const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)]; - const orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight); - - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + // Create orders to match + orderLeft = { + makerAddress: makerAddressLeft, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + makerAssetAmount: new BigNumber(10), + takerAddress: '0x0000000000000000000000000000000000000000', takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: new BigNumber(1), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + feeRecipientAddress, + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + senderAddress: '0x0000000000000000000000000000000000000000', + expirationTimeSeconds: new BigNumber(1549498915), + salt: new BigNumber(217), + }; + orderRight = { + makerAddress: makerAddressRight, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: new BigNumber(1), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18), - }); - - - //matchOrdersTxData = TransactionEncoder.matchOrdersTx(signedOrderLeft, signedOrderRight); + takerAddress: '0x0000000000000000000000000000000000000000', + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + takerAssetAmount: new BigNumber(8), + feeRecipientAddress, + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + senderAddress: '0x0000000000000000000000000000000000000000', + expirationTimeSeconds: new BigNumber(1549498915), + salt: new BigNumber(50010), + }; + const orderFactoryLeft = new OrderFactory(privateKeyLeft, orderLeft); + signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ exchangeAddress }); + const orderFactoryRight = new OrderFactory(privateKeyRight, orderRight); + signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ exchangeAddress }); + // Encode match orders transaction + contractAddresses = await migrateOnceAsync(); + await blockchainLifecycle.startAsync(); + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + contractAddresses, + blockPollingIntervalMs: 10, + }; + const contractWrappers = new ContractWrappers(provider, config); + const transactionEncoder = await contractWrappers.exchange.transactionEncoderAsync(); + matchOrdersTxData = transactionEncoder.matchOrdersTx(signedOrderLeft, signedOrderRight); }); describe('decode', () => { - /* it('should successfully decode DutchAuction.matchOrders txData', async () => { - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName: 'DutchAuction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); - console.log(decodedTxData); + const contractName = 'DutchAuction'; + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName }); + const expectedFunctionName = 'matchOrders'; + const expectedFunctionArguments = { + buyOrder: orderLeft, + sellOrder: orderRight, + buySignature: signedOrderLeft.signature, + sellSignature: signedOrderRight.signature, + }; + expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); + expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature); + expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); }); - it('should successfully decode Exchange.matchOrders txData', async () => { - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName: 'Exchange' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); - console.log(decodedTxData); + it('should successfully decode Exchange.matchOrders txData (and distinguish from DutchAuction.matchOrders)', async () => { + const contractName = 'Exchange'; + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName }); + const expectedFunctionName = 'matchOrders'; + const expectedFunctionArguments = { + leftOrder: orderLeft, + rightOrder: orderRight, + leftSignature: signedOrderLeft.signature, + rightSignature: signedOrderRight.signature, + }; + expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); + expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature); + expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); }); it('should successfully decode Exchange.matchOrders, using exchange address to identify the exchange contract', async () => { - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); - console.log(decodedTxData); + const contractAddress = contractAddresses.exchange; + const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractAddress }); + const expectedFunctionName = 'matchOrders'; + const expectedFunctionArguments = { + leftOrder: orderLeft, + rightOrder: orderRight, + leftSignature: signedOrderLeft.signature, + rightSignature: signedOrderRight.signature, + }; + expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); + expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature); + expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); }); it('should throw if cannot decode txData', async () => { - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, {networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); - console.log(decodedTxData); - });*/ + const contractAddress = contractAddresses.exchange; + const badTxData = '0x01020304'; + expect(() => { + ZeroExTransactionDecoder.decode(badTxData, { contractAddress }); + }).to.throw("No functions registered for selector '0x01020304'"); + }); }); describe('addABI', () => { - /*it('should successfully add a new ABI', async () => { - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName: 'DutchAuction' }); //{networkId: 1, contractAddress: '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'}); - console.log(decodedTxData); - });*/ + it('should successfully add a new ABI', async () => { + // Add new ABI + const abi: MethodAbi = { + name: 'foobar', + type: 'function', + inputs: [ + { + name: 'addr', + type: 'address', + }, + ], + outputs: [ + { + name: 'butter', + type: 'string', + }, + ], + constant: false, + payable: false, + stateMutability: 'pure', + }; + const contractName = 'newContract'; + const contractAddress = addressUtils.generatePseudoRandomAddress(); + const networkId = 1; + const contractInfo = [ + { + contractAddress, + networkId, + }, + ]; + ZeroExTransactionDecoder.addABI([abi], contractName, contractInfo); + // Create some tx data + const foobarEncoder = new AbiEncoder.Method(abi); + const foobarSignature = foobarEncoder.getSignature(); + const foobarTxData = foobarEncoder.encode([contractAddress]); + // Decode tx data using contract name + const decodedTxData = ZeroExTransactionDecoder.decode(foobarTxData, { contractName }); + const expectedFunctionName = abi.name; + const expectedFunctionArguments = { + addr: contractAddress, + }; + expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); + expect(decodedTxData.functionSignature).to.be.equal(foobarSignature); + expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); + // Decode tx data using contract address + const decodedTxDataDecodedWithAddress = ZeroExTransactionDecoder.decode(foobarTxData, { contractAddress }); + expect(decodedTxDataDecodedWithAddress).to.be.deep.equal(decodedTxData); + }); }); }); diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts index 318504c37c..b700cd944d 100644 --- a/packages/utils/src/address_utils.ts +++ b/packages/utils/src/address_utils.ts @@ -65,5 +65,5 @@ export const addressUtils = { const randomBuff = sha3(randomBigNum.toString()); const randomAddress = `0x${randomBuff.slice(0, 20).toString('hex')}`; return randomAddress; - } + }, }; diff --git a/packages/utils/src/transaction_decoder.ts b/packages/utils/src/transaction_decoder.ts index 2c3b96c72b..dd1b4d19a0 100644 --- a/packages/utils/src/transaction_decoder.ts +++ b/packages/utils/src/transaction_decoder.ts @@ -30,7 +30,11 @@ export class TransactionDecoder { * @param contractName Name of contract that encapsulates the ABI definitions (optional). * @param deploymentInfos A collection of network/address pairs where this contract is deployed (optional). */ - public addABI(abiDefinitions: AbiDefinition[], contractName?: string, deploymentInfos?: DeployedContractInfo[]): void { + public addABI( + abiDefinitions: AbiDefinition[], + contractName?: string, + deploymentInfos?: DeployedContractInfo[], + ): void { // Disregard definitions that are not functions const functionAbis = _.filter(abiDefinitions, abiEntry => { return abiEntry.type === 'function'; @@ -70,7 +74,7 @@ export class TransactionDecoder { * @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments. */ public decode(txData: string, txProperties_?: TransactionProperties): TransactionData { - // Lookup + // Lookup const functionSelector = TransactionDecoder._getFunctionSelector(txData); const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; diff --git a/packages/utils/test/transaction_decoder_test.ts b/packages/utils/test/transaction_decoder_test.ts index f214b17338..bc40f48408 100644 --- a/packages/utils/test/transaction_decoder_test.ts +++ b/packages/utils/test/transaction_decoder_test.ts @@ -1,12 +1,9 @@ import * as chai from 'chai'; import 'mocha'; - import { chaiSetup } from './utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -describe.only('TransactionDecoder', () => { - -}); +describe.only('TransactionDecoder', () => {}); From 3d2babd059551fc0e1a571d3cf1cb544ec85f52c Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 17:21:19 -0800 Subject: [PATCH 25/39] Tests for transaction decoder --- .../utils/test/transaction_decoder_test.ts | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/utils/test/transaction_decoder_test.ts b/packages/utils/test/transaction_decoder_test.ts index bc40f48408..3845bb134c 100644 --- a/packages/utils/test/transaction_decoder_test.ts +++ b/packages/utils/test/transaction_decoder_test.ts @@ -1,9 +1,61 @@ import * as chai from 'chai'; +import { MethodAbi } from 'ethereum-types'; import 'mocha'; import { chaiSetup } from './utils/chai_setup'; +import { AbiEncoder, TransactionDecoder } from '../src'; chaiSetup.configure(); const expect = chai.expect; -describe.only('TransactionDecoder', () => {}); +describe('TransactionDecoder', () => { + it('should successfully add a new ABI and decode tx data for it', async () => { + // Add new ABI + const abi: MethodAbi = { + name: 'foobar', + type: 'function', + inputs: [ + { + name: 'addr', + type: 'address', + }, + ], + outputs: [ + { + name: 'butter', + type: 'string', + }, + ], + constant: false, + payable: false, + stateMutability: 'pure', + }; + const contractName = 'newContract'; + const contractAddress = '0x0001020304050607080900010203040506070809'; + const networkId = 1; + const contractInfo = [ + { + contractAddress, + networkId, + }, + ]; + const transactionDecoder = new TransactionDecoder(); + transactionDecoder.addABI([abi], contractName, contractInfo); + // Create some tx data + const foobarEncoder = new AbiEncoder.Method(abi); + const foobarSignature = foobarEncoder.getSignature(); + const foobarTxData = foobarEncoder.encode([contractAddress]); + // Decode tx data using contract name + const decodedTxData = transactionDecoder.decode(foobarTxData, { contractName }); + const expectedFunctionName = abi.name; + const expectedFunctionArguments = { + addr: contractAddress, + }; + expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); + expect(decodedTxData.functionSignature).to.be.equal(foobarSignature); + expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); + // Decode tx data using contract address + const decodedTxDataDecodedWithAddress = transactionDecoder.decode(foobarTxData, { contractAddress }); + expect(decodedTxDataDecodedWithAddress).to.be.deep.equal(decodedTxData); + }); +}); From 831a628379aa444ffe944b4f73913b59cb300d76 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 17:42:54 -0800 Subject: [PATCH 26/39] ran linter --- packages/utils/src/address_utils.ts | 5 +++-- packages/utils/src/transaction_decoder.ts | 2 ++ packages/utils/test/transaction_decoder_test.ts | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts index b700cd944d..b269c26b4a 100644 --- a/packages/utils/src/address_utils.ts +++ b/packages/utils/src/address_utils.ts @@ -1,4 +1,4 @@ -import { addHexPrefix, stripHexPrefix, sha3 } from 'ethereumjs-util'; +import { addHexPrefix, sha3, stripHexPrefix } from 'ethereumjs-util'; import * as jsSHA3 from 'js-sha3'; import * as _ from 'lodash'; @@ -63,7 +63,8 @@ export const addressUtils = { generatePseudoRandomAddress(): string { const randomBigNum = addressUtils.generatePseudoRandomSalt(); const randomBuff = sha3(randomBigNum.toString()); - const randomAddress = `0x${randomBuff.slice(0, 20).toString('hex')}`; + const addressLengthInBytes = 20; + const randomAddress = `0x${randomBuff.slice(0, addressLengthInBytes).toString('hex')}`; return randomAddress; }, }; diff --git a/packages/utils/src/transaction_decoder.ts b/packages/utils/src/transaction_decoder.ts index dd1b4d19a0..9d567286ea 100644 --- a/packages/utils/src/transaction_decoder.ts +++ b/packages/utils/src/transaction_decoder.ts @@ -36,9 +36,11 @@ export class TransactionDecoder { deploymentInfos?: DeployedContractInfo[], ): void { // Disregard definitions that are not functions + // tslint:disable no-unnecessary-type-assertion const functionAbis = _.filter(abiDefinitions, abiEntry => { return abiEntry.type === 'function'; }) as MethodAbi[]; + // tslint:enable no-unnecessary-type-assertion // Record function ABI's _.each(functionAbis, functionAbi => { const abiEncoder = new AbiEncoder.Method(functionAbi); diff --git a/packages/utils/test/transaction_decoder_test.ts b/packages/utils/test/transaction_decoder_test.ts index 3845bb134c..725ad50327 100644 --- a/packages/utils/test/transaction_decoder_test.ts +++ b/packages/utils/test/transaction_decoder_test.ts @@ -2,9 +2,10 @@ import * as chai from 'chai'; import { MethodAbi } from 'ethereum-types'; import 'mocha'; -import { chaiSetup } from './utils/chai_setup'; import { AbiEncoder, TransactionDecoder } from '../src'; +import { chaiSetup } from './utils/chai_setup'; + chaiSetup.configure(); const expect = chai.expect; From 6bde77bb57e1d0526154cc6b2b3bb0ff70c1d2b0 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 17:50:37 -0800 Subject: [PATCH 27/39] fix doc generation in contract-wrappers --- packages/contract-wrappers/src/index.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 2693668960..fd4b9d357e 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -72,6 +72,12 @@ export { AssetProxyId, } from '@0x/types'; +export { + DeployedContractInfo, + TransactionData, + TransactionProperties +} from '@0x/utils'; + export { BlockParamLiteral, BlockParam, From 6406126ae356a6dd1102cf603d4ce00333c9fd62 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 23:47:40 -0800 Subject: [PATCH 28/39] Merged tx decoder into AbiDecoder in utils and merged zeroex tx decoder into ContractWrappers. --- .../src/contract_wrappers.ts | 12 +- packages/contract-wrappers/src/index.ts | 7 - .../src/utils/zeroex_transaction_decoder.ts | 88 ------------- ...coder_test.ts => calldata_decoder_test.ts} | 87 ++----------- packages/utils/CHANGELOG.json | 9 ++ packages/utils/src/abi_decoder.ts | 121 +++++++++++++++--- packages/utils/src/index.ts | 1 - packages/utils/src/transaction_decoder.ts | 112 ---------------- packages/utils/src/types.ts | 15 --- ...on_decoder_test.ts => abi_decoder_test.ts} | 32 ++--- 10 files changed, 145 insertions(+), 339 deletions(-) delete mode 100644 packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts rename packages/contract-wrappers/test/{zeroex_transaction_decoder_test.ts => calldata_decoder_test.ts} (58%) delete mode 100644 packages/utils/src/transaction_decoder.ts rename packages/utils/test/{transaction_decoder_test.ts => abi_decoder_test.ts} (53%) diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts index 4e594593e5..63de61a471 100644 --- a/packages/contract-wrappers/src/contract_wrappers.ts +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -1,4 +1,5 @@ import { + DutchAuction, ERC20Proxy, ERC20Token, ERC721Proxy, @@ -8,6 +9,7 @@ import { OrderValidator, WETH9, } from '@0x/contract-artifacts'; +import { AbiDecoder } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { Provider } from 'ethereum-types'; import * as _ from 'lodash'; @@ -87,6 +89,7 @@ export class ContractWrappers { }; this._web3Wrapper = new Web3Wrapper(provider, txDefaults); const artifactsArray = [ + DutchAuction, ERC20Proxy, ERC20Token, ERC721Proxy, @@ -97,7 +100,7 @@ export class ContractWrappers { WETH9, ]; _.forEach(artifactsArray, artifact => { - this._web3Wrapper.abiDecoder.addABI(artifact.compilerOutput.abi); + this._web3Wrapper.abiDecoder.addABI(artifact.compilerOutput.abi, artifact.contractName); }); const blockPollingIntervalMs = _.isUndefined(config.blockPollingIntervalMs) ? constants.DEFAULT_BLOCK_POLLING_INTERVAL @@ -168,4 +171,11 @@ export class ContractWrappers { public getProvider(): Provider { return this._web3Wrapper.getProvider(); } + /** + * Get the provider instance currently used by contract-wrappers + * @return Web3 provider instance + */ + public getAbiDecoder(): AbiDecoder { + return this._web3Wrapper.abiDecoder; + } } diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index fd4b9d357e..69bbe3c91b 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -37,7 +37,6 @@ export { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapp export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper'; export { TransactionEncoder } from './utils/transaction_encoder'; -export { ZeroExTransactionDecoder } from './utils/zeroex_transaction_decoder'; export { ContractWrappersError, @@ -72,12 +71,6 @@ export { AssetProxyId, } from '@0x/types'; -export { - DeployedContractInfo, - TransactionData, - TransactionProperties -} from '@0x/utils'; - export { BlockParamLiteral, BlockParam, diff --git a/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts b/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts deleted file mode 100644 index 17f06497c4..0000000000 --- a/packages/contract-wrappers/src/utils/zeroex_transaction_decoder.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { getContractAddressesForNetworkOrThrow, NetworkId } from '@0x/contract-addresses'; -import * as ContractArtifacts from '@0x/contract-artifacts'; -import { SimpleContractArtifact } from '@0x/types'; -import { AbiDefinition, ContractAbi } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { - DeployedContractInfo, - DeployedContractInfoByName, - TransactionData, - TransactionDecoder, - TransactionProperties, -} from '@0x/utils'; - -export class ZeroExTransactionDecoder extends TransactionDecoder { - private static _instance: ZeroExTransactionDecoder; - /** - * Adds a set of ABI definitions, after which transaction data targeting these ABI's can be decoded. - * Additional properties can be included to disambiguate similar ABI's. For example, if two functions - * have the same signature but different parameter names, then their ABI definitions can be disambiguated - * by specifying a contract name. - * @param abiDefinitions ABI definitions for a given contract. - * @param contractName Name of contract that encapsulates the ABI definitions (optional). - * @param deploymentInfos A collection of network/address pairs where this contract is deployed (optional). - */ - public static addABI( - abiDefinitions: AbiDefinition[], - contractName: string, - deploymentInfos?: DeployedContractInfo[], - ): void { - const instance = ZeroExTransactionDecoder._getInstance(); - instance.addABI(abiDefinitions, contractName, deploymentInfos); - } - /** - * Decodes transaction data for a known ABI. - * @param txData hex-encoded transaction data. - * @param txProperties Properties about the transaction used to disambiguate similar ABI's (optional). - * @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments. - */ - public static decode(calldata: string, txProperties?: TransactionProperties): TransactionData { - const instance = ZeroExTransactionDecoder._getInstance(); - const decodedCalldata = instance.decode(calldata, txProperties); - return decodedCalldata; - } - /** - * Gets instance for singleton. - * @return singleton instance. - */ - private static _getInstance(): ZeroExTransactionDecoder { - if (!ZeroExTransactionDecoder._instance) { - ZeroExTransactionDecoder._instance = new ZeroExTransactionDecoder(); - } - return ZeroExTransactionDecoder._instance; - } - /** - * Adds all known contract ABI's defined by the @0x/Artifacts package, along with known 0x - * contract addresses. - */ - private constructor() { - super(); - // Load addresses by contract name - const deployedContractInfoByName: DeployedContractInfoByName = {}; - _.each(NetworkId, (networkId: any) => { - if (typeof networkId !== 'number') { - return; - } - const contractAddressesForNetwork = getContractAddressesForNetworkOrThrow(networkId); - _.each(contractAddressesForNetwork, (contractAddress: string, contractName: string) => { - const contractNameLowercase = _.toLower(contractName); - if (_.isUndefined(deployedContractInfoByName[contractNameLowercase])) { - deployedContractInfoByName[contractNameLowercase] = []; - } - deployedContractInfoByName[contractNameLowercase].push({ - contractAddress, - networkId, - }); - }); - }); - // Load contract artifacts - _.each(ContractArtifacts, (contractArtifactAsJson: any) => { - const conractArtifact = contractArtifactAsJson as SimpleContractArtifact; - const contractName = conractArtifact.contractName; - const contractNameLowercase = _.toLower(contractName); - const contractAbi: ContractAbi = conractArtifact.compilerOutput.abi; - this.addABI(contractAbi, contractName, deployedContractInfoByName[contractNameLowercase]); - }); - } -} diff --git a/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts b/packages/contract-wrappers/test/calldata_decoder_test.ts similarity index 58% rename from packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts rename to packages/contract-wrappers/test/calldata_decoder_test.ts index 83c810c3af..d44e13a898 100644 --- a/packages/contract-wrappers/test/zeroex_transaction_decoder_test.ts +++ b/packages/contract-wrappers/test/calldata_decoder_test.ts @@ -2,14 +2,12 @@ import { constants, OrderFactory } from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; -import { AbiEncoder, addressUtils, BigNumber } from '@0x/utils'; +import { addressUtils, BigNumber } from '@0x/utils'; import * as chai from 'chai'; -import { MethodAbi } from 'ethereum-types'; import * as _ from 'lodash'; import 'mocha'; import { ContractAddresses, ContractWrappers } from '../src'; -import { ZeroExTransactionDecoder } from '../src/utils/zeroex_transaction_decoder'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; @@ -20,7 +18,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -describe.only('ZeroExTransactionDecoder', () => { +describe('ABI Decoding Calldata', () => { const defaultERC20MakerAssetAddress = addressUtils.generatePseudoRandomAddress(); const matchOrdersSignature = 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)'; @@ -30,6 +28,7 @@ describe.only('ZeroExTransactionDecoder', () => { let orderRight = {}; let matchOrdersTxData: string; let contractAddresses: ContractAddresses; + let contractWrappers: ContractWrappers; before(async () => { // Create accounts @@ -80,15 +79,15 @@ describe.only('ZeroExTransactionDecoder', () => { contractAddresses, blockPollingIntervalMs: 10, }; - const contractWrappers = new ContractWrappers(provider, config); + contractWrappers = new ContractWrappers(provider, config); const transactionEncoder = await contractWrappers.exchange.transactionEncoderAsync(); matchOrdersTxData = transactionEncoder.matchOrdersTx(signedOrderLeft, signedOrderRight); }); describe('decode', () => { - it('should successfully decode DutchAuction.matchOrders txData', async () => { + it('should successfully decode DutchAuction.matchOrders calldata', async () => { const contractName = 'DutchAuction'; - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName }); + const decodedTxData = contractWrappers.getAbiDecoder().tryDecodeCalldata(matchOrdersTxData, contractName); const expectedFunctionName = 'matchOrders'; const expectedFunctionArguments = { buyOrder: orderLeft, @@ -100,9 +99,9 @@ describe.only('ZeroExTransactionDecoder', () => { expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature); expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); }); - it('should successfully decode Exchange.matchOrders txData (and distinguish from DutchAuction.matchOrders)', async () => { + it('should successfully decode Exchange.matchOrders calldata (and distinguish from DutchAuction.matchOrders)', async () => { const contractName = 'Exchange'; - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractName }); + const decodedTxData = contractWrappers.getAbiDecoder().tryDecodeCalldata(matchOrdersTxData, contractName); const expectedFunctionName = 'matchOrders'; const expectedFunctionArguments = { leftOrder: orderLeft, @@ -114,77 +113,11 @@ describe.only('ZeroExTransactionDecoder', () => { expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature); expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); }); - it('should successfully decode Exchange.matchOrders, using exchange address to identify the exchange contract', async () => { - const contractAddress = contractAddresses.exchange; - const decodedTxData = ZeroExTransactionDecoder.decode(matchOrdersTxData, { contractAddress }); - const expectedFunctionName = 'matchOrders'; - const expectedFunctionArguments = { - leftOrder: orderLeft, - rightOrder: orderRight, - leftSignature: signedOrderLeft.signature, - rightSignature: signedOrderRight.signature, - }; - expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); - expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature); - expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); - }); - it('should throw if cannot decode txData', async () => { - const contractAddress = contractAddresses.exchange; + it('should throw if cannot decode calldata', async () => { const badTxData = '0x01020304'; expect(() => { - ZeroExTransactionDecoder.decode(badTxData, { contractAddress }); + contractWrappers.getAbiDecoder().tryDecodeCalldata(badTxData); }).to.throw("No functions registered for selector '0x01020304'"); }); }); - - describe('addABI', () => { - it('should successfully add a new ABI', async () => { - // Add new ABI - const abi: MethodAbi = { - name: 'foobar', - type: 'function', - inputs: [ - { - name: 'addr', - type: 'address', - }, - ], - outputs: [ - { - name: 'butter', - type: 'string', - }, - ], - constant: false, - payable: false, - stateMutability: 'pure', - }; - const contractName = 'newContract'; - const contractAddress = addressUtils.generatePseudoRandomAddress(); - const networkId = 1; - const contractInfo = [ - { - contractAddress, - networkId, - }, - ]; - ZeroExTransactionDecoder.addABI([abi], contractName, contractInfo); - // Create some tx data - const foobarEncoder = new AbiEncoder.Method(abi); - const foobarSignature = foobarEncoder.getSignature(); - const foobarTxData = foobarEncoder.encode([contractAddress]); - // Decode tx data using contract name - const decodedTxData = ZeroExTransactionDecoder.decode(foobarTxData, { contractName }); - const expectedFunctionName = abi.name; - const expectedFunctionArguments = { - addr: contractAddress, - }; - expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); - expect(decodedTxData.functionSignature).to.be.equal(foobarSignature); - expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); - // Decode tx data using contract address - const decodedTxDataDecodedWithAddress = ZeroExTransactionDecoder.decode(foobarTxData, { contractAddress }); - expect(decodedTxDataDecodedWithAddress).to.be.deep.equal(decodedTxData); - }); - }); }); diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index 9ce2a4c52f..95f61a43c7 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "4.1.0", + "changes": [ + { + "note": "Added method decoding to AbiDecoder", + "pr": 1569 + } + ] + }, { "version": "4.0.4", "changes": [ diff --git a/packages/utils/src/abi_decoder.ts b/packages/utils/src/abi_decoder.ts index 28b6418d88..c817ad2859 100644 --- a/packages/utils/src/abi_decoder.ts +++ b/packages/utils/src/abi_decoder.ts @@ -6,28 +6,49 @@ import { EventParameter, LogEntry, LogWithDecodedArgs, + MethodAbi, RawLog, SolidityTypes, } from 'ethereum-types'; import * as ethers from 'ethers'; import * as _ from 'lodash'; +import { AbiEncoder } from '.'; import { addressUtils } from './address_utils'; import { BigNumber } from './configured_bignumber'; +import { FunctionInfoBySelector, TransactionData } from './types'; /** * AbiDecoder allows you to decode event logs given a set of supplied contract ABI's. It takes the contract's event * signature from the ABI and attempts to decode the logs using it. */ export class AbiDecoder { - private readonly _methodIds: { [signatureHash: string]: { [numIndexedArgs: number]: EventAbi } } = {}; + private readonly _eventIds: { [signatureHash: string]: { [numIndexedArgs: number]: EventAbi } } = {}; + private readonly _functionInfoBySelector: FunctionInfoBySelector = {}; + /** + * Retrieves the function selector from tranasction data. + * @param calldata hex-encoded transaction data. + * @return hex-encoded function selector. + */ + private static _getFunctionSelector(calldata: string): string { + const functionSelectorLength = 10; + if (!calldata.startsWith('0x') || calldata.length < functionSelectorLength) { + throw new Error( + `Malformed transaction data. Must include a hex prefix '0x' and 4-byte function selector. Got '${calldata}'`, + ); + } + const functionSelector = calldata.substr(0, functionSelectorLength); + return functionSelector; + } /** * Instantiate an AbiDecoder * @param abiArrays An array of contract ABI's * @return AbiDecoder instance */ constructor(abiArrays: AbiDefinition[][]) { - _.forEach(abiArrays, this.addABI.bind(this)); + _.each(abiArrays, (abi) => { + this.addABI(abi); + }); } /** * Attempt to decode a log given the ABI's the AbiDecoder knows about. @@ -37,10 +58,10 @@ export class AbiDecoder { public tryToDecodeLogOrNoop(log: LogEntry): LogWithDecodedArgs | RawLog { const methodId = log.topics[0]; const numIndexedArgs = log.topics.length - 1; - if (_.isUndefined(this._methodIds[methodId]) || _.isUndefined(this._methodIds[methodId][numIndexedArgs])) { + if (_.isUndefined(this._eventIds[methodId]) || _.isUndefined(this._eventIds[methodId][numIndexedArgs])) { return log; } - const event = this._methodIds[methodId][numIndexedArgs]; + const event = this._eventIds[methodId][numIndexedArgs]; const ethersInterface = new ethers.utils.Interface([event]); const decodedParams: DecodedLogArgs = {}; let topicsIndex = 1; @@ -89,25 +110,93 @@ export class AbiDecoder { } } /** - * Add additional ABI definitions to the AbiDecoder - * @param abiArray An array of ABI definitions to add to the AbiDecoder + * Decodes transaction data for a known ABI. + * @param calldata hex-encoded transaction data. + * @param contractName used to disambiguate similar ABI's (optional). + * @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments. */ - public addABI(abiArray: AbiDefinition[]): void { + public tryDecodeCalldata(calldata: string, contractName?: string): TransactionData { + const functionSelector = AbiDecoder._getFunctionSelector(calldata); + const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; + if (_.isUndefined(candidateFunctionInfos)) { + throw new Error(`No functions registered for selector '${functionSelector}'`); + } + const functionInfo = _.find(candidateFunctionInfos, txDecoder => { + return ( + (_.isUndefined(contractName) || + _.toLower(txDecoder.contractName) === _.toLower(contractName))); + }); + if (_.isUndefined(functionInfo)) { + throw new Error(`No function registered with selector ${functionSelector} and contract name ${contractName}.`); + } else if (_.isUndefined(functionInfo.abiEncoder)) { + throw new Error( + `Function ABI Encoder is not defined, for function registered with selector ${functionSelector} and contract name ${contractName}.`, + ); + } + const functionName = functionInfo.abiEncoder.getDataItem().name; + const functionSignature = functionInfo.abiEncoder.getSignatureType(); + const functionArguments = functionInfo.abiEncoder.decode(calldata); + const decodedCalldata = { + functionName, + functionSignature, + functionArguments, + }; + return decodedCalldata; + } + /** + * Adds a set of ABI definitions, after which transaction data targeting these ABI's can be decoded. + * Additional properties can be included to disambiguate similar ABI's. For example, if two functions + * have the same signature but different parameter names, then their ABI definitions can be disambiguated + * by specifying a contract name. + * @param abiDefinitions ABI definitions for a given contract. + * @param contractName Name of contract that encapsulates the ABI definitions (optional). + */ + public addABI( + abiArray: AbiDefinition[], + contractName?: string + ): void { if (_.isUndefined(abiArray)) { return; } const ethersInterface = new ethers.utils.Interface(abiArray); _.map(abiArray, (abi: AbiDefinition) => { - if (abi.type === AbiType.Event) { - // tslint:disable-next-line:no-unnecessary-type-assertion - const eventAbi = abi as EventAbi; - const topic = ethersInterface.events[eventAbi.name].topic; - const numIndexedArgs = _.reduce(eventAbi.inputs, (sum, input) => (input.indexed ? sum + 1 : sum), 0); - this._methodIds[topic] = { - ...this._methodIds[topic], - [numIndexedArgs]: eventAbi, - }; + switch (abi.type) { + case AbiType.Event: + this._addEventABI(abi as EventAbi, ethersInterface); + break; + + case AbiType.Function: + this._addMethodABI(abi as MethodAbi, contractName); + break; + + default: + // ignore other types + break; } }); } + private _addEventABI(abi: EventAbi, ethersInterface: ethers.utils.Interface): void { + // tslint:disable-next-line:no-unnecessary-type-assertion + const eventAbi = abi as EventAbi; + const topic = ethersInterface.events[eventAbi.name].topic; + const numIndexedArgs = _.reduce(eventAbi.inputs, (sum, input) => (input.indexed ? sum + 1 : sum), 0); + this._eventIds[topic] = { + ...this._eventIds[topic], + [numIndexedArgs]: eventAbi, + }; + } + private _addMethodABI(methodAbi: MethodAbi, contractName?: string): void { + const abiEncoder = new AbiEncoder.Method(methodAbi); + const functionSelector = abiEncoder.getSelector(); + if (!(functionSelector in this._functionInfoBySelector)) { + this._functionInfoBySelector[functionSelector] = []; + } + // Recored a copy of this ABI for each deployment + const functionSignature = abiEncoder.getSignature(); + this._functionInfoBySelector[functionSelector].push({ + functionSignature, + abiEncoder, + contractName, + }); + } } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 6f1c14c832..467129d2ba 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -12,4 +12,3 @@ export { fetchAsync } from './fetch_async'; export { signTypedDataUtils } from './sign_typed_data_utils'; export import AbiEncoder = require('./abi_encoder'); export * from './types'; -export { TransactionDecoder } from './transaction_decoder'; diff --git a/packages/utils/src/transaction_decoder.ts b/packages/utils/src/transaction_decoder.ts deleted file mode 100644 index 9d567286ea..0000000000 --- a/packages/utils/src/transaction_decoder.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { AbiDefinition, MethodAbi } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { AbiEncoder } from '.'; -import { DeployedContractInfo, FunctionInfoBySelector, TransactionData, TransactionProperties } from './types'; - -export class TransactionDecoder { - private readonly _functionInfoBySelector: FunctionInfoBySelector = {}; - /** - * Retrieves the function selector from tranasction data. - * @param txData hex-encoded transaction data. - * @return hex-encoded function selector. - */ - private static _getFunctionSelector(txData: string): string { - const functionSelectorLength = 10; - if (!txData.startsWith('0x') || txData.length < functionSelectorLength) { - throw new Error( - `Malformed transaction data. Must include a hex prefix '0x' and 4-byte function selector. Got '${txData}'`, - ); - } - const functionSelector = txData.substr(0, functionSelectorLength); - return functionSelector; - } - /** - * Adds a set of ABI definitions, after which transaction data targeting these ABI's can be decoded. - * Additional properties can be included to disambiguate similar ABI's. For example, if two functions - * have the same signature but different parameter names, then their ABI definitions can be disambiguated - * by specifying a contract name. - * @param abiDefinitions ABI definitions for a given contract. - * @param contractName Name of contract that encapsulates the ABI definitions (optional). - * @param deploymentInfos A collection of network/address pairs where this contract is deployed (optional). - */ - public addABI( - abiDefinitions: AbiDefinition[], - contractName?: string, - deploymentInfos?: DeployedContractInfo[], - ): void { - // Disregard definitions that are not functions - // tslint:disable no-unnecessary-type-assertion - const functionAbis = _.filter(abiDefinitions, abiEntry => { - return abiEntry.type === 'function'; - }) as MethodAbi[]; - // tslint:enable no-unnecessary-type-assertion - // Record function ABI's - _.each(functionAbis, functionAbi => { - const abiEncoder = new AbiEncoder.Method(functionAbi); - const functionSelector = abiEncoder.getSelector(); - if (!(functionSelector in this._functionInfoBySelector)) { - this._functionInfoBySelector[functionSelector] = []; - } - // Recored a copy of this ABI for each deployment - const functionSignature = abiEncoder.getSignature(); - _.each(deploymentInfos, deploymentInfo => { - this._functionInfoBySelector[functionSelector].push({ - functionSignature, - abiEncoder, - contractName, - contractAddress: deploymentInfo.contractAddress, - networkId: deploymentInfo.networkId, - }); - }); - // There is no deployment info for this contract; record it without an address/network id - if (_.isEmpty(deploymentInfos)) { - this._functionInfoBySelector[functionSelector].push({ - functionSignature, - abiEncoder, - contractName, - }); - } - }); - } - /** - * Decodes transaction data for a known ABI. - * @param txData hex-encoded transaction data. - * @param txProperties Properties about the transaction used to disambiguate similar ABI's (optional). - * @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments. - */ - public decode(txData: string, txProperties_?: TransactionProperties): TransactionData { - // Lookup - const functionSelector = TransactionDecoder._getFunctionSelector(txData); - const txProperties = _.isUndefined(txProperties_) ? {} : txProperties_; - const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; - if (_.isUndefined(candidateFunctionInfos)) { - throw new Error(`No functions registered for selector '${functionSelector}'`); - } - const functionInfo = _.find(candidateFunctionInfos, txDecoder => { - return ( - (_.isUndefined(txProperties.contractName) || - _.toLower(txDecoder.contractName) === _.toLower(txProperties.contractName)) && - (_.isUndefined(txProperties.contractAddress) || - txDecoder.contractAddress === txProperties.contractAddress) && - (_.isUndefined(txProperties.networkId) || txDecoder.networkId === txProperties.networkId) - ); - }); - if (_.isUndefined(functionInfo)) { - throw new Error(`No function registered with properties: ${JSON.stringify(txProperties)}.`); - } else if (_.isUndefined(functionInfo.abiEncoder)) { - throw new Error( - `Function ABI Encoder is not defined, for function with properties: ${JSON.stringify(txProperties)}.`, - ); - } - const functionName = functionInfo.abiEncoder.getDataItem().name; - const functionSignature = functionInfo.abiEncoder.getSignatureType(); - const functionArguments = functionInfo.abiEncoder.decode(txData); - const decodedCalldata = { - functionName, - functionSignature, - functionArguments, - }; - return decodedCalldata; - } -} diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index 2510a9ec21..cd7a13d53d 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -17,18 +17,3 @@ export interface TransactionData { functionSignature: string; functionArguments: any; } - -export interface TransactionProperties { - contractName?: string; - contractAddress?: string; - networkId?: number; -} - -export interface DeployedContractInfo { - contractAddress: string; - networkId: number; -} - -export interface DeployedContractInfoByName { - [index: string]: DeployedContractInfo[]; -} diff --git a/packages/utils/test/transaction_decoder_test.ts b/packages/utils/test/abi_decoder_test.ts similarity index 53% rename from packages/utils/test/transaction_decoder_test.ts rename to packages/utils/test/abi_decoder_test.ts index 725ad50327..346bfdfd3d 100644 --- a/packages/utils/test/transaction_decoder_test.ts +++ b/packages/utils/test/abi_decoder_test.ts @@ -2,22 +2,22 @@ import * as chai from 'chai'; import { MethodAbi } from 'ethereum-types'; import 'mocha'; -import { AbiEncoder, TransactionDecoder } from '../src'; +import { AbiEncoder, AbiDecoder } from '../src'; import { chaiSetup } from './utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -describe('TransactionDecoder', () => { - it('should successfully add a new ABI and decode tx data for it', async () => { +describe('AbiDecoder', () => { + it('should successfully add a new ABI and decode calldata for it', async () => { // Add new ABI const abi: MethodAbi = { name: 'foobar', type: 'function', inputs: [ { - name: 'addr', + name: 'testAddress', type: 'address', }, ], @@ -32,31 +32,19 @@ describe('TransactionDecoder', () => { stateMutability: 'pure', }; const contractName = 'newContract'; - const contractAddress = '0x0001020304050607080900010203040506070809'; - const networkId = 1; - const contractInfo = [ - { - contractAddress, - networkId, - }, - ]; - const transactionDecoder = new TransactionDecoder(); - transactionDecoder.addABI([abi], contractName, contractInfo); + const testAddress = '0x0001020304050607080900010203040506070809'; + const abiDecoder = new AbiDecoder([]); + abiDecoder.addABI([abi], contractName); // Create some tx data const foobarEncoder = new AbiEncoder.Method(abi); const foobarSignature = foobarEncoder.getSignature(); - const foobarTxData = foobarEncoder.encode([contractAddress]); + const foobarTxData = foobarEncoder.encode([testAddress]); // Decode tx data using contract name - const decodedTxData = transactionDecoder.decode(foobarTxData, { contractName }); + const decodedTxData = abiDecoder.tryDecodeCalldata(foobarTxData, contractName); const expectedFunctionName = abi.name; - const expectedFunctionArguments = { - addr: contractAddress, - }; + const expectedFunctionArguments = {testAddress}; expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); expect(decodedTxData.functionSignature).to.be.equal(foobarSignature); expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); - // Decode tx data using contract address - const decodedTxDataDecodedWithAddress = transactionDecoder.decode(foobarTxData, { contractAddress }); - expect(decodedTxDataDecodedWithAddress).to.be.deep.equal(decodedTxData); }); }); From c72e3667b8366f8b125091d704a67c1de91985ff Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 6 Feb 2019 23:59:25 -0800 Subject: [PATCH 29/39] ran prettier and linter --- .../src/contract_wrappers.ts | 2 +- packages/utils/src/abi_decoder.ts | 21 ++++++++++--------- packages/utils/test/abi_decoder_test.ts | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts index 63de61a471..bd9a377eda 100644 --- a/packages/contract-wrappers/src/contract_wrappers.ts +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -171,7 +171,7 @@ export class ContractWrappers { public getProvider(): Provider { return this._web3Wrapper.getProvider(); } - /** + /** * Get the provider instance currently used by contract-wrappers * @return Web3 provider instance */ diff --git a/packages/utils/src/abi_decoder.ts b/packages/utils/src/abi_decoder.ts index c817ad2859..e8a222229b 100644 --- a/packages/utils/src/abi_decoder.ts +++ b/packages/utils/src/abi_decoder.ts @@ -46,7 +46,7 @@ export class AbiDecoder { * @return AbiDecoder instance */ constructor(abiArrays: AbiDefinition[][]) { - _.each(abiArrays, (abi) => { + _.each(abiArrays, abi => { this.addABI(abi); }); } @@ -122,12 +122,12 @@ export class AbiDecoder { throw new Error(`No functions registered for selector '${functionSelector}'`); } const functionInfo = _.find(candidateFunctionInfos, txDecoder => { - return ( - (_.isUndefined(contractName) || - _.toLower(txDecoder.contractName) === _.toLower(contractName))); + return _.isUndefined(contractName) || _.toLower(txDecoder.contractName) === _.toLower(contractName); }); if (_.isUndefined(functionInfo)) { - throw new Error(`No function registered with selector ${functionSelector} and contract name ${contractName}.`); + throw new Error( + `No function registered with selector ${functionSelector} and contract name ${contractName}.`, + ); } else if (_.isUndefined(functionInfo.abiEncoder)) { throw new Error( `Function ABI Encoder is not defined, for function registered with selector ${functionSelector} and contract name ${contractName}.`, @@ -151,10 +151,7 @@ export class AbiDecoder { * @param abiDefinitions ABI definitions for a given contract. * @param contractName Name of contract that encapsulates the ABI definitions (optional). */ - public addABI( - abiArray: AbiDefinition[], - contractName?: string - ): void { + public addABI(abiArray: AbiDefinition[], contractName?: string): void { if (_.isUndefined(abiArray)) { return; } @@ -162,16 +159,20 @@ export class AbiDecoder { _.map(abiArray, (abi: AbiDefinition) => { switch (abi.type) { case AbiType.Event: + // tslint:disable no-unnecessary-type-assertion this._addEventABI(abi as EventAbi, ethersInterface); + // tslint:enable no-unnecessary-type-assertion break; case AbiType.Function: + // tslint:disable no-unnecessary-type-assertion this._addMethodABI(abi as MethodAbi, contractName); + // tslint:enable no-unnecessary-type-assertion break; default: // ignore other types - break; + break; } }); } diff --git a/packages/utils/test/abi_decoder_test.ts b/packages/utils/test/abi_decoder_test.ts index 346bfdfd3d..6014346143 100644 --- a/packages/utils/test/abi_decoder_test.ts +++ b/packages/utils/test/abi_decoder_test.ts @@ -2,7 +2,7 @@ import * as chai from 'chai'; import { MethodAbi } from 'ethereum-types'; import 'mocha'; -import { AbiEncoder, AbiDecoder } from '../src'; +import { AbiDecoder, AbiEncoder } from '../src'; import { chaiSetup } from './utils/chai_setup'; @@ -42,7 +42,7 @@ describe('AbiDecoder', () => { // Decode tx data using contract name const decodedTxData = abiDecoder.tryDecodeCalldata(foobarTxData, contractName); const expectedFunctionName = abi.name; - const expectedFunctionArguments = {testAddress}; + const expectedFunctionArguments = { testAddress }; expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); expect(decodedTxData.functionSignature).to.be.equal(foobarSignature); expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); From 93c128ee21465249a3d9c6549d1765a79f071200 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 7 Feb 2019 01:09:56 -0800 Subject: [PATCH 30/39] Added exports for doc generation --- packages/0x.js/src/index.ts | 2 +- packages/contract-wrappers/src/index.ts | 4 ++++ packages/web3-wrapper/src/index.ts | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 006e4cf29a..41a4401852 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -68,7 +68,7 @@ export { MetamaskSubprovider, } from '@0x/subproviders'; -export { AbiDecoder } from '@0x/utils'; +export { AbiDecoder, TransactionData } from '@0x/utils'; export { BigNumber } from '@0x/utils'; diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 69bbe3c91b..75faac9fb7 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -38,6 +38,8 @@ export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper'; export { TransactionEncoder } from './utils/transaction_encoder'; +export { AbiDecoder, TransactionData } from '@0x/utils'; + export { ContractWrappersError, ForwarderWrapperError, @@ -83,6 +85,8 @@ export { JSONRPCResponseError, AbiDefinition, LogWithDecodedArgs, + LogEntry, + RawLog, FunctionAbi, EventAbi, EventParameter, diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts index 4d20ba9bed..2a66e01b56 100644 --- a/packages/web3-wrapper/src/index.ts +++ b/packages/web3-wrapper/src/index.ts @@ -1,7 +1,7 @@ export { Web3Wrapper } from './web3_wrapper'; export { marshaller } from './marshaller'; -export { AbiDecoder } from '@0x/utils'; +export { AbiDecoder, TransactionData } from '@0x/utils'; export { BlockParam, From 56e7e7d6444d96d48bcea655281d801f202b5f5e Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 7 Feb 2019 15:41:14 -0800 Subject: [PATCH 31/39] updated exports for contract wrappers --- packages/contract-wrappers/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 75faac9fb7..5eaf6118f8 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -86,6 +86,9 @@ export { AbiDefinition, LogWithDecodedArgs, LogEntry, + DecodedLogEntry, + DecodedLogEntryEvent, + LogEntryEvent, RawLog, FunctionAbi, EventAbi, From 6d0dc47157f7cc17f1f3da7a1960456e4ae9bede Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 7 Feb 2019 15:43:54 -0800 Subject: [PATCH 32/39] updated changelog for contract wrappers --- packages/contract-wrappers/CHANGELOG.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 73c8e60709..6e0d1ca4b4 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "7.1.0", + "changes": [ + { + "note": "Added calldata decoding to ContractWrappers", + "pr": 1569 + } + ] + }, { "version": "7.0.2", "changes": [ From 500b4940a320c842394c996f15495c1cdc7b3547 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 8 Feb 2019 14:46:39 -0800 Subject: [PATCH 33/39] Improvements and conventions in utils package + abi decoder --- packages/0x.js/src/index.ts | 12 ++++- .../src/contract_wrappers.ts | 4 +- packages/contract-wrappers/src/index.ts | 2 +- .../src/utils/transaction_encoder.ts | 4 +- .../test/calldata_decoder_test.ts | 18 ++++--- packages/utils/src/abi_decoder.ts | 52 +++++++++---------- packages/utils/src/address_utils.ts | 26 +--------- packages/utils/src/types.ts | 4 +- packages/utils/test/abi_decoder_test.ts | 2 +- packages/web3-wrapper/src/index.ts | 2 +- 10 files changed, 57 insertions(+), 69 deletions(-) diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 41a4401852..082b097277 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -1,6 +1,12 @@ export { ContractAddresses } from '@0x/contract-addresses'; -export { assetDataUtils, signatureUtils, generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils'; +export { + assetDataUtils, + signatureUtils, + generatePseudoRandomSalt, + orderHashUtils, + transactionHashUtils, +} from '@0x/order-utils'; export { ContractWrappers, @@ -68,7 +74,7 @@ export { MetamaskSubprovider, } from '@0x/subproviders'; -export { AbiDecoder, TransactionData } from '@0x/utils'; +export { AbiDecoder, DecodedCalldata } from '@0x/utils'; export { BigNumber } from '@0x/utils'; @@ -92,6 +98,8 @@ export { OrderRelevantState, Stats, DutchAuctionDetails, + ZeroExTransaction, + SignedZeroExTransaction, } from '@0x/types'; export { diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts index bd9a377eda..f43dc5d265 100644 --- a/packages/contract-wrappers/src/contract_wrappers.ts +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -172,8 +172,8 @@ export class ContractWrappers { return this._web3Wrapper.getProvider(); } /** - * Get the provider instance currently used by contract-wrappers - * @return Web3 provider instance + * Get the abi decoder instance currently used by contract-wrappers + * @return AbiDecoder instance */ public getAbiDecoder(): AbiDecoder { return this._web3Wrapper.abiDecoder; diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 5eaf6118f8..5fc400edf6 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -38,7 +38,7 @@ export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper'; export { TransactionEncoder } from './utils/transaction_encoder'; -export { AbiDecoder, TransactionData } from '@0x/utils'; +export { AbiDecoder, DecodedCalldata } from '@0x/utils'; export { ContractWrappersError, diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts index 8bf67ee56c..0832ee73a9 100644 --- a/packages/contract-wrappers/src/utils/transaction_encoder.ts +++ b/packages/contract-wrappers/src/utils/transaction_encoder.ts @@ -248,8 +248,8 @@ export class TransactionEncoder { * @return Hex encoded abi of the function call. */ public matchOrdersTx(leftOrder: SignedOrder, rightOrder: SignedOrder): string { - assert.doesConformToSchema('order', leftOrder, schemas.orderSchema); - assert.doesConformToSchema('order', rightOrder, schemas.orderSchema); + assert.doesConformToSchema('leftOrder', leftOrder, schemas.orderSchema); + assert.doesConformToSchema('rightOrder', rightOrder, schemas.orderSchema); const abiEncodedData = this._getExchangeContract().matchOrders.getABIEncodedTransactionData( leftOrder, rightOrder, diff --git a/packages/contract-wrappers/test/calldata_decoder_test.ts b/packages/contract-wrappers/test/calldata_decoder_test.ts index d44e13a898..ba1539ef55 100644 --- a/packages/contract-wrappers/test/calldata_decoder_test.ts +++ b/packages/contract-wrappers/test/calldata_decoder_test.ts @@ -33,12 +33,12 @@ describe('ABI Decoding Calldata', () => { before(async () => { // Create accounts const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const [makerAddressLeft, makerAddressRight] = accounts.slice(0, 2); + const [makerAddressLeft, makerAddressRight] = accounts; + const [privateKeyLeft, privateKeyRight] = constants.TESTRPC_PRIVATE_KEYS; const exchangeAddress = addressUtils.generatePseudoRandomAddress(); const feeRecipientAddress = addressUtils.generatePseudoRandomAddress(); - const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)]; - const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)]; - // Create orders to match + // Create orders to match. + // Values are arbitrary, with the exception of maker addresses (generated above). orderLeft = { makerAddress: makerAddressLeft, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), @@ -87,7 +87,9 @@ describe('ABI Decoding Calldata', () => { describe('decode', () => { it('should successfully decode DutchAuction.matchOrders calldata', async () => { const contractName = 'DutchAuction'; - const decodedTxData = contractWrappers.getAbiDecoder().tryDecodeCalldata(matchOrdersTxData, contractName); + const decodedTxData = contractWrappers + .getAbiDecoder() + .decodeCalldataOrThrow(matchOrdersTxData, contractName); const expectedFunctionName = 'matchOrders'; const expectedFunctionArguments = { buyOrder: orderLeft, @@ -101,7 +103,9 @@ describe('ABI Decoding Calldata', () => { }); it('should successfully decode Exchange.matchOrders calldata (and distinguish from DutchAuction.matchOrders)', async () => { const contractName = 'Exchange'; - const decodedTxData = contractWrappers.getAbiDecoder().tryDecodeCalldata(matchOrdersTxData, contractName); + const decodedTxData = contractWrappers + .getAbiDecoder() + .decodeCalldataOrThrow(matchOrdersTxData, contractName); const expectedFunctionName = 'matchOrders'; const expectedFunctionArguments = { leftOrder: orderLeft, @@ -116,7 +120,7 @@ describe('ABI Decoding Calldata', () => { it('should throw if cannot decode calldata', async () => { const badTxData = '0x01020304'; expect(() => { - contractWrappers.getAbiDecoder().tryDecodeCalldata(badTxData); + contractWrappers.getAbiDecoder().decodeCalldataOrThrow(badTxData); }).to.throw("No functions registered for selector '0x01020304'"); }); }); diff --git a/packages/utils/src/abi_decoder.ts b/packages/utils/src/abi_decoder.ts index e8a222229b..b764e45b87 100644 --- a/packages/utils/src/abi_decoder.ts +++ b/packages/utils/src/abi_decoder.ts @@ -16,7 +16,7 @@ import * as _ from 'lodash'; import { AbiEncoder } from '.'; import { addressUtils } from './address_utils'; import { BigNumber } from './configured_bignumber'; -import { FunctionInfoBySelector, TransactionData } from './types'; +import { DecodedCalldata, SelectorToFunctionInfo } from './types'; /** * AbiDecoder allows you to decode event logs given a set of supplied contract ABI's. It takes the contract's event @@ -24,17 +24,17 @@ import { FunctionInfoBySelector, TransactionData } from './types'; */ export class AbiDecoder { private readonly _eventIds: { [signatureHash: string]: { [numIndexedArgs: number]: EventAbi } } = {}; - private readonly _functionInfoBySelector: FunctionInfoBySelector = {}; + private readonly _selectorToFunctionInfo: SelectorToFunctionInfo = {}; /** - * Retrieves the function selector from tranasction data. - * @param calldata hex-encoded transaction data. + * Retrieves the function selector from calldata. + * @param calldata hex-encoded calldata. * @return hex-encoded function selector. */ private static _getFunctionSelector(calldata: string): string { const functionSelectorLength = 10; if (!calldata.startsWith('0x') || calldata.length < functionSelectorLength) { throw new Error( - `Malformed transaction data. Must include a hex prefix '0x' and 4-byte function selector. Got '${calldata}'`, + `Malformed calldata. Must include a hex prefix '0x' and 4-byte function selector. Got '${calldata}'`, ); } const functionSelector = calldata.substr(0, functionSelectorLength); @@ -56,12 +56,12 @@ export class AbiDecoder { * @return The decoded log if the requisite ABI was available. Otherwise the log unaltered. */ public tryToDecodeLogOrNoop(log: LogEntry): LogWithDecodedArgs | RawLog { - const methodId = log.topics[0]; + const eventId = log.topics[0]; const numIndexedArgs = log.topics.length - 1; - if (_.isUndefined(this._eventIds[methodId]) || _.isUndefined(this._eventIds[methodId][numIndexedArgs])) { + if (_.isUndefined(this._eventIds[eventId]) || _.isUndefined(this._eventIds[eventId][numIndexedArgs])) { return log; } - const event = this._eventIds[methodId][numIndexedArgs]; + const event = this._eventIds[eventId][numIndexedArgs]; const ethersInterface = new ethers.utils.Interface([event]); const decodedParams: DecodedLogArgs = {}; let topicsIndex = 1; @@ -110,19 +110,21 @@ export class AbiDecoder { } } /** - * Decodes transaction data for a known ABI. - * @param calldata hex-encoded transaction data. + * Decodes calldata for a known ABI. + * @param calldata hex-encoded calldata. * @param contractName used to disambiguate similar ABI's (optional). - * @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments. + * @return Decoded calldata. Includes: function name and signature, along with the decoded arguments. */ - public tryDecodeCalldata(calldata: string, contractName?: string): TransactionData { + public decodeCalldataOrThrow(calldata: string, contractName?: string): DecodedCalldata { const functionSelector = AbiDecoder._getFunctionSelector(calldata); - const candidateFunctionInfos = this._functionInfoBySelector[functionSelector]; + const candidateFunctionInfos = this._selectorToFunctionInfo[functionSelector]; if (_.isUndefined(candidateFunctionInfos)) { throw new Error(`No functions registered for selector '${functionSelector}'`); } - const functionInfo = _.find(candidateFunctionInfos, txDecoder => { - return _.isUndefined(contractName) || _.toLower(txDecoder.contractName) === _.toLower(contractName); + const functionInfo = _.find(candidateFunctionInfos, candidateFunctionInfo => { + return ( + _.isUndefined(contractName) || _.toLower(contractName) === _.toLower(candidateFunctionInfo.contractName) + ); }); if (_.isUndefined(functionInfo)) { throw new Error( @@ -144,12 +146,14 @@ export class AbiDecoder { return decodedCalldata; } /** - * Adds a set of ABI definitions, after which transaction data targeting these ABI's can be decoded. + * Adds a set of ABI definitions, after which calldata and logs targeting these ABI's can be decoded. * Additional properties can be included to disambiguate similar ABI's. For example, if two functions * have the same signature but different parameter names, then their ABI definitions can be disambiguated * by specifying a contract name. * @param abiDefinitions ABI definitions for a given contract. * @param contractName Name of contract that encapsulates the ABI definitions (optional). + * This can be used when decoding calldata to disambiguate methods with + * the same signature but different parameter names. */ public addABI(abiArray: AbiDefinition[], contractName?: string): void { if (_.isUndefined(abiArray)) { @@ -159,15 +163,13 @@ export class AbiDecoder { _.map(abiArray, (abi: AbiDefinition) => { switch (abi.type) { case AbiType.Event: - // tslint:disable no-unnecessary-type-assertion + // tslint:disable-next-line:no-unnecessary-type-assertion this._addEventABI(abi as EventAbi, ethersInterface); - // tslint:enable no-unnecessary-type-assertion break; case AbiType.Function: - // tslint:disable no-unnecessary-type-assertion + // tslint:disable-next-line:no-unnecessary-type-assertion this._addMethodABI(abi as MethodAbi, contractName); - // tslint:enable no-unnecessary-type-assertion break; default: @@ -176,9 +178,7 @@ export class AbiDecoder { } }); } - private _addEventABI(abi: EventAbi, ethersInterface: ethers.utils.Interface): void { - // tslint:disable-next-line:no-unnecessary-type-assertion - const eventAbi = abi as EventAbi; + private _addEventABI(eventAbi: EventAbi, ethersInterface: ethers.utils.Interface): void { const topic = ethersInterface.events[eventAbi.name].topic; const numIndexedArgs = _.reduce(eventAbi.inputs, (sum, input) => (input.indexed ? sum + 1 : sum), 0); this._eventIds[topic] = { @@ -189,12 +189,12 @@ export class AbiDecoder { private _addMethodABI(methodAbi: MethodAbi, contractName?: string): void { const abiEncoder = new AbiEncoder.Method(methodAbi); const functionSelector = abiEncoder.getSelector(); - if (!(functionSelector in this._functionInfoBySelector)) { - this._functionInfoBySelector[functionSelector] = []; + if (!(functionSelector in this._selectorToFunctionInfo)) { + this._selectorToFunctionInfo[functionSelector] = []; } // Recored a copy of this ABI for each deployment const functionSignature = abiEncoder.getSignature(); - this._functionInfoBySelector[functionSelector].push({ + this._selectorToFunctionInfo[functionSelector].push({ functionSignature, abiEncoder, contractName, diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts index b269c26b4a..1fc9604085 100644 --- a/packages/utils/src/address_utils.ts +++ b/packages/utils/src/address_utils.ts @@ -1,13 +1,10 @@ -import { addHexPrefix, sha3, stripHexPrefix } from 'ethereumjs-util'; +import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util'; import * as jsSHA3 from 'js-sha3'; import * as _ from 'lodash'; -import { BigNumber } from './configured_bignumber'; - const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i; const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/; const ADDRESS_LENGTH = 40; -const MAX_DIGITS_IN_UNSIGNED_256_INT = 78; export const addressUtils = { isChecksumAddress(address: string): boolean { @@ -46,25 +43,4 @@ export const addressUtils = { padZeros(address: string): string { return addHexPrefix(_.padStart(stripHexPrefix(address), ADDRESS_LENGTH, '0')); }, - /** - * Generates a pseudo-random 256-bit salt. - * The salt can be included in a 0x order, ensuring that the order generates a unique orderHash - * and will not collide with other outstanding orders that are identical in all other parameters. - * @return A pseudo-random 256-bit number that can be used as a salt. - */ - generatePseudoRandomSalt(): BigNumber { - // BigNumber.random returns a pseudo-random number between 0 & 1 with a passed in number of decimal places. - // Source: https://mikemcl.github.io/bignumber.js/#random - const randomNumber = BigNumber.random(MAX_DIGITS_IN_UNSIGNED_256_INT); - const factor = new BigNumber(10).pow(MAX_DIGITS_IN_UNSIGNED_256_INT - 1); - const salt = randomNumber.times(factor); - return salt; - }, - generatePseudoRandomAddress(): string { - const randomBigNum = addressUtils.generatePseudoRandomSalt(); - const randomBuff = sha3(randomBigNum.toString()); - const addressLengthInBytes = 20; - const randomAddress = `0x${randomBuff.slice(0, addressLengthInBytes).toString('hex')}`; - return randomAddress; - }, }; diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index cd7a13d53d..32e11efa22 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -8,11 +8,11 @@ export interface FunctionInfo { abiEncoder?: AbiEncoder.Method; } -export interface FunctionInfoBySelector { +export interface SelectorToFunctionInfo { [index: string]: FunctionInfo[]; } -export interface TransactionData { +export interface DecodedCalldata { functionName: string; functionSignature: string; functionArguments: any; diff --git a/packages/utils/test/abi_decoder_test.ts b/packages/utils/test/abi_decoder_test.ts index 6014346143..81fed1060e 100644 --- a/packages/utils/test/abi_decoder_test.ts +++ b/packages/utils/test/abi_decoder_test.ts @@ -40,7 +40,7 @@ describe('AbiDecoder', () => { const foobarSignature = foobarEncoder.getSignature(); const foobarTxData = foobarEncoder.encode([testAddress]); // Decode tx data using contract name - const decodedTxData = abiDecoder.tryDecodeCalldata(foobarTxData, contractName); + const decodedTxData = abiDecoder.decodeCalldataOrThrow(foobarTxData, contractName); const expectedFunctionName = abi.name; const expectedFunctionArguments = { testAddress }; expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts index 2a66e01b56..a634084552 100644 --- a/packages/web3-wrapper/src/index.ts +++ b/packages/web3-wrapper/src/index.ts @@ -1,7 +1,7 @@ export { Web3Wrapper } from './web3_wrapper'; export { marshaller } from './marshaller'; -export { AbiDecoder, TransactionData } from '@0x/utils'; +export { AbiDecoder, DecodedCalldata } from '@0x/utils'; export { BlockParam, From a9aaae7f97b2684107d158db0c1530749e096b3e Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 8 Feb 2019 16:04:45 -0800 Subject: [PATCH 34/39] Deduped random value generation from salt generation --- packages/order-utils/src/salt.ts | 10 ++-------- packages/utils/src/address_utils.ts | 11 ++++++++++- packages/utils/src/index.ts | 1 + packages/utils/src/random.ts | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 packages/utils/src/random.ts diff --git a/packages/order-utils/src/salt.ts b/packages/order-utils/src/salt.ts index 95df66c995..a7cc4aea05 100644 --- a/packages/order-utils/src/salt.ts +++ b/packages/order-utils/src/salt.ts @@ -1,6 +1,4 @@ -import { BigNumber } from '@0x/utils'; - -const MAX_DIGITS_IN_UNSIGNED_256_INT = 78; +import { BigNumber, generatePseudoRandom256BitNumber } from '@0x/utils'; /** * Generates a pseudo-random 256-bit salt. @@ -9,10 +7,6 @@ const MAX_DIGITS_IN_UNSIGNED_256_INT = 78; * @return A pseudo-random 256-bit number that can be used as a salt. */ export function generatePseudoRandomSalt(): BigNumber { - // BigNumber.random returns a pseudo-random number between 0 & 1 with a passed in number of decimal places. - // Source: https://mikemcl.github.io/bignumber.js/#random - const randomNumber = BigNumber.random(MAX_DIGITS_IN_UNSIGNED_256_INT); - const factor = new BigNumber(10).pow(MAX_DIGITS_IN_UNSIGNED_256_INT - 1); - const salt = randomNumber.times(factor).integerValue(); + const salt = generatePseudoRandom256BitNumber(); return salt; } diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts index 1fc9604085..361e35cd81 100644 --- a/packages/utils/src/address_utils.ts +++ b/packages/utils/src/address_utils.ts @@ -1,7 +1,9 @@ -import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util'; +import { addHexPrefix, sha3, stripHexPrefix } from 'ethereumjs-util'; import * as jsSHA3 from 'js-sha3'; import * as _ from 'lodash'; +import { generatePseudoRandom256BitNumber } from './random'; + const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i; const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/; const ADDRESS_LENGTH = 40; @@ -43,4 +45,11 @@ export const addressUtils = { padZeros(address: string): string { return addHexPrefix(_.padStart(stripHexPrefix(address), ADDRESS_LENGTH, '0')); }, + generatePseudoRandomAddress(): string { + const randomBigNum = generatePseudoRandom256BitNumber(); + const randomBuff = sha3(randomBigNum.toString()); + const addressLengthInBytes = 20; + const randomAddress = `0x${randomBuff.slice(0, addressLengthInBytes).toString('hex')}`; + return randomAddress; + }, }; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 467129d2ba..f9c2693fe0 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -12,3 +12,4 @@ export { fetchAsync } from './fetch_async'; export { signTypedDataUtils } from './sign_typed_data_utils'; export import AbiEncoder = require('./abi_encoder'); export * from './types'; +export { generatePseudoRandom256BitNumber } from './random'; diff --git a/packages/utils/src/random.ts b/packages/utils/src/random.ts new file mode 100644 index 0000000000..69243bab84 --- /dev/null +++ b/packages/utils/src/random.ts @@ -0,0 +1,16 @@ +import { BigNumber } from './configured_bignumber'; + +const MAX_DIGITS_IN_UNSIGNED_256_INT = 78; + +/** + * Generates a pseudo-random 256-bit number. + * @return A pseudo-random 256-bit number. + */ +export function generatePseudoRandom256BitNumber(): BigNumber { + // BigNumber.random returns a pseudo-random number between 0 & 1 with a passed in number of decimal places. + // Source: https://mikemcl.github.io/bignumber.js/#random + const randomNumber = BigNumber.random(MAX_DIGITS_IN_UNSIGNED_256_INT); + const factor = new BigNumber(10).pow(MAX_DIGITS_IN_UNSIGNED_256_INT - 1); + const randomNumberScaledTo256Bits = randomNumber.times(factor).integerValue(); + return randomNumberScaledTo256Bits; +} From 233869ed80a1f2836834d20adbc478d2e9b26b54 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 8 Feb 2019 16:33:08 -0800 Subject: [PATCH 35/39] updated changelog.json for 0x.js / order-utils / web3-wrapper --- packages/0x.js/CHANGELOG.json | 9 +++++++++ packages/order-utils/CHANGELOG.json | 9 +++++++++ packages/web3-wrapper/CHANGELOG.json | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 69381d7a00..e94d87de16 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "5.0.0", + "changes": [ + { + "note": "Export `transactionHashUtils`, `DecodedCalldata`, `ZeroExTransaction`, and `SignedZeroExTransaction`", + "pr": 1569 + } + ] + }, { "version": "4.0.3", "changes": [ diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 0028ea0c76..8f984538b5 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "6.1.0", + "changes": [ + { + "note": "Updated implementation of `generatePseudoRandomSalt` to use generator from @0x/utils", + "pr": 1569 + } + ] + }, { "version": "6.0.1", "changes": [ diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index 49dbe5a64f..bf1dedc00f 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "5.0.0", + "changes": [ + { + "note": "Export `DecodedCalldata` from @0x/utils", + "pr": 1569 + } + ] + }, { "version": "4.0.2", "changes": [ From e9bfc44b90722d24a5e1cc0d6a153be7875fae01 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sat, 9 Feb 2019 17:28:52 +0000 Subject: [PATCH 36/39] Remove react deps from highlight --- yarn.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index ab5d224923..b4aae4b0af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13518,8 +13518,6 @@ react-highlight@0xproject/react-highlight#react-peer-deps: dependencies: highlight.js "^9.11.0" highlightjs-solidity "^1.0.5" - react "^16.4.2" - react-dom "^16.4.2" react-hot-loader@^4.3.3: version "4.3.4" From 28d9fdf798cf3e30ad37b3994408001eace219f7 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sat, 9 Feb 2019 18:44:28 +0000 Subject: [PATCH 37/39] Updated CHANGELOGS --- contracts/asset-proxy/CHANGELOG.json | 9 +++++++++ contracts/asset-proxy/CHANGELOG.md | 4 ++++ contracts/erc20/CHANGELOG.json | 9 +++++++++ contracts/erc20/CHANGELOG.md | 4 ++++ contracts/erc721/CHANGELOG.json | 9 +++++++++ contracts/erc721/CHANGELOG.md | 4 ++++ contracts/exchange-forwarder/CHANGELOG.json | 9 +++++++++ contracts/exchange-forwarder/CHANGELOG.md | 4 ++++ contracts/exchange-libs/CHANGELOG.json | 9 +++++++++ contracts/exchange-libs/CHANGELOG.md | 4 ++++ contracts/exchange/CHANGELOG.json | 9 +++++++++ contracts/exchange/CHANGELOG.md | 4 ++++ contracts/extensions/CHANGELOG.json | 9 +++++++++ contracts/extensions/CHANGELOG.md | 4 ++++ contracts/multisig/CHANGELOG.json | 9 +++++++++ contracts/multisig/CHANGELOG.md | 4 ++++ contracts/test-utils/CHANGELOG.json | 9 +++++++++ contracts/test-utils/CHANGELOG.md | 4 ++++ contracts/utils/CHANGELOG.json | 9 +++++++++ contracts/utils/CHANGELOG.md | 4 ++++ packages/0x.js/CHANGELOG.json | 3 ++- packages/0x.js/CHANGELOG.md | 4 ++++ packages/abi-gen-wrappers/CHANGELOG.json | 9 +++++++++ packages/abi-gen-wrappers/CHANGELOG.md | 4 ++++ packages/abi-gen/CHANGELOG.json | 9 +++++++++ packages/abi-gen/CHANGELOG.md | 4 ++++ packages/assert/CHANGELOG.json | 9 +++++++++ packages/assert/CHANGELOG.md | 4 ++++ packages/asset-buyer/CHANGELOG.json | 9 +++++++++ packages/asset-buyer/CHANGELOG.md | 4 ++++ packages/base-contract/CHANGELOG.json | 9 +++++++++ packages/base-contract/CHANGELOG.md | 4 ++++ packages/connect/CHANGELOG.json | 9 +++++++++ packages/connect/CHANGELOG.md | 4 ++++ packages/contract-wrappers/CHANGELOG.json | 3 ++- packages/contract-wrappers/CHANGELOG.md | 4 ++++ packages/contracts-gen/CHANGELOG.json | 9 +++++++++ packages/contracts-gen/CHANGELOG.md | 4 ++++ packages/dev-utils/CHANGELOG.json | 3 ++- packages/dev-utils/CHANGELOG.md | 4 ++++ packages/fill-scenarios/CHANGELOG.json | 9 +++++++++ packages/fill-scenarios/CHANGELOG.md | 4 ++++ packages/json-schemas/CHANGELOG.json | 9 +++++++++ packages/json-schemas/CHANGELOG.md | 4 ++++ packages/migrations/CHANGELOG.json | 9 +++++++++ packages/migrations/CHANGELOG.md | 4 ++++ packages/order-utils/CHANGELOG.json | 3 ++- packages/order-utils/CHANGELOG.md | 4 ++++ packages/order-watcher/CHANGELOG.json | 9 +++++++++ packages/order-watcher/CHANGELOG.md | 4 ++++ packages/react-docs/CHANGELOG.json | 9 +++++++++ packages/react-docs/CHANGELOG.md | 4 ++++ packages/react-shared/CHANGELOG.json | 9 +++++++++ packages/react-shared/CHANGELOG.md | 4 ++++ packages/sol-compiler/CHANGELOG.json | 9 +++++++++ packages/sol-compiler/CHANGELOG.md | 4 ++++ packages/sol-coverage/CHANGELOG.json | 9 +++++++++ packages/sol-coverage/CHANGELOG.md | 4 ++++ packages/sol-doc/CHANGELOG.json | 9 +++++++++ packages/sol-doc/CHANGELOG.md | 4 ++++ packages/sol-profiler/CHANGELOG.json | 9 +++++++++ packages/sol-profiler/CHANGELOG.md | 4 ++++ packages/sol-trace/CHANGELOG.json | 9 +++++++++ packages/sol-trace/CHANGELOG.md | 4 ++++ packages/sol-tracing-utils/CHANGELOG.json | 9 +++++++++ packages/sol-tracing-utils/CHANGELOG.md | 4 ++++ packages/sra-spec/CHANGELOG.json | 9 +++++++++ packages/sra-spec/CHANGELOG.md | 4 ++++ packages/subproviders/CHANGELOG.json | 9 +++++++++ packages/subproviders/CHANGELOG.md | 4 ++++ packages/utils/CHANGELOG.json | 3 ++- packages/utils/CHANGELOG.md | 8 ++++++++ packages/web3-wrapper/CHANGELOG.json | 3 ++- packages/web3-wrapper/CHANGELOG.md | 4 ++++ 74 files changed, 443 insertions(+), 6 deletions(-) diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json index de7e90d662..e4a573f18e 100644 --- a/contracts/asset-proxy/CHANGELOG.json +++ b/contracts/asset-proxy/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.4", "changes": [ diff --git a/contracts/asset-proxy/CHANGELOG.md b/contracts/asset-proxy/CHANGELOG.md index fcf5202c65..d1fc0c74c2 100644 --- a/contracts/asset-proxy/CHANGELOG.md +++ b/contracts/asset-proxy/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.5 - _February 9, 2019_ + + * Dependencies updated + ## v1.0.4 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/erc20/CHANGELOG.json b/contracts/erc20/CHANGELOG.json index 972de20389..e3962e8fc5 100644 --- a/contracts/erc20/CHANGELOG.json +++ b/contracts/erc20/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.4", "changes": [ diff --git a/contracts/erc20/CHANGELOG.md b/contracts/erc20/CHANGELOG.md index 6583096724..87cfc418ae 100644 --- a/contracts/erc20/CHANGELOG.md +++ b/contracts/erc20/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.5 - _February 9, 2019_ + + * Dependencies updated + ## v1.0.4 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/erc721/CHANGELOG.json b/contracts/erc721/CHANGELOG.json index 5f3e08dd35..cae644730d 100644 --- a/contracts/erc721/CHANGELOG.json +++ b/contracts/erc721/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.4", "changes": [ diff --git a/contracts/erc721/CHANGELOG.md b/contracts/erc721/CHANGELOG.md index 5886f10b8c..4bc5404084 100644 --- a/contracts/erc721/CHANGELOG.md +++ b/contracts/erc721/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.5 - _February 9, 2019_ + + * Dependencies updated + ## v1.0.4 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/exchange-forwarder/CHANGELOG.json b/contracts/exchange-forwarder/CHANGELOG.json index 338adde3d1..b06678f2cf 100644 --- a/contracts/exchange-forwarder/CHANGELOG.json +++ b/contracts/exchange-forwarder/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.4", "changes": [ diff --git a/contracts/exchange-forwarder/CHANGELOG.md b/contracts/exchange-forwarder/CHANGELOG.md index 24bb6da5be..aacc015dc5 100644 --- a/contracts/exchange-forwarder/CHANGELOG.md +++ b/contracts/exchange-forwarder/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.5 - _February 9, 2019_ + + * Dependencies updated + ## v1.0.4 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/exchange-libs/CHANGELOG.json b/contracts/exchange-libs/CHANGELOG.json index 5de06a7140..9d2abeeb11 100644 --- a/contracts/exchange-libs/CHANGELOG.json +++ b/contracts/exchange-libs/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.4", "changes": [ diff --git a/contracts/exchange-libs/CHANGELOG.md b/contracts/exchange-libs/CHANGELOG.md index 46e970e6f5..27723a7b5d 100644 --- a/contracts/exchange-libs/CHANGELOG.md +++ b/contracts/exchange-libs/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.5 - _February 9, 2019_ + + * Dependencies updated + ## v1.0.4 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/exchange/CHANGELOG.json b/contracts/exchange/CHANGELOG.json index 02c614b1a6..50ea203fce 100644 --- a/contracts/exchange/CHANGELOG.json +++ b/contracts/exchange/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.4", "changes": [ diff --git a/contracts/exchange/CHANGELOG.md b/contracts/exchange/CHANGELOG.md index f265cd96fe..2e48cdbb83 100644 --- a/contracts/exchange/CHANGELOG.md +++ b/contracts/exchange/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.5 - _February 9, 2019_ + + * Dependencies updated + ## v1.0.4 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json index 8a1335c518..5e9395b2bd 100644 --- a/contracts/extensions/CHANGELOG.json +++ b/contracts/extensions/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/contracts/extensions/CHANGELOG.md b/contracts/extensions/CHANGELOG.md index 34137efdbc..dc5cd5fe3d 100644 --- a/contracts/extensions/CHANGELOG.md +++ b/contracts/extensions/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/multisig/CHANGELOG.json b/contracts/multisig/CHANGELOG.json index 0c1b52f2f3..e5d1a3a55e 100644 --- a/contracts/multisig/CHANGELOG.json +++ b/contracts/multisig/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/contracts/multisig/CHANGELOG.md b/contracts/multisig/CHANGELOG.md index 7c7b0ae4ae..636c1da6f2 100644 --- a/contracts/multisig/CHANGELOG.md +++ b/contracts/multisig/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/test-utils/CHANGELOG.json b/contracts/test-utils/CHANGELOG.json index 812bff732a..0393512716 100644 --- a/contracts/test-utils/CHANGELOG.json +++ b/contracts/test-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "3.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.3", "changes": [ diff --git a/contracts/test-utils/CHANGELOG.md b/contracts/test-utils/CHANGELOG.md index b3fc98ab6b..3568f5ba30 100644 --- a/contracts/test-utils/CHANGELOG.md +++ b/contracts/test-utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v3.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/contracts/utils/CHANGELOG.json b/contracts/utils/CHANGELOG.json index bc887914b2..664d00746d 100644 --- a/contracts/utils/CHANGELOG.json +++ b/contracts/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/contracts/utils/CHANGELOG.md b/contracts/utils/CHANGELOG.md index dd0b91a61f..91cb0f2ea8 100644 --- a/contracts/utils/CHANGELOG.md +++ b/contracts/utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index e94d87de16..4167cdaef5 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Export `transactionHashUtils`, `DecodedCalldata`, `ZeroExTransaction`, and `SignedZeroExTransaction`", "pr": 1569 } - ] + ], + "timestamp": 1549733923 }, { "version": "4.0.3", diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md index 7c14fb5863..d4b8da4460 100644 --- a/packages/0x.js/CHANGELOG.md +++ b/packages/0x.js/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v5.0.0 - _February 9, 2019_ + + * Export `transactionHashUtils`, `DecodedCalldata`, `ZeroExTransaction`, and `SignedZeroExTransaction` (#1569) + ## v4.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/abi-gen-wrappers/CHANGELOG.json b/packages/abi-gen-wrappers/CHANGELOG.json index a7793c5d5a..cd5ff0cadf 100644 --- a/packages/abi-gen-wrappers/CHANGELOG.json +++ b/packages/abi-gen-wrappers/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "3.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.2", "changes": [ diff --git a/packages/abi-gen-wrappers/CHANGELOG.md b/packages/abi-gen-wrappers/CHANGELOG.md index 93e11736c4..17ed224e5b 100644 --- a/packages/abi-gen-wrappers/CHANGELOG.md +++ b/packages/abi-gen-wrappers/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v3.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/abi-gen/CHANGELOG.json b/packages/abi-gen/CHANGELOG.json index d7770c06df..ff3ba53d85 100644 --- a/packages/abi-gen/CHANGELOG.json +++ b/packages/abi-gen/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.2", "changes": [ diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md index 65c914cc9c..bd3c0add32 100644 --- a/packages/abi-gen/CHANGELOG.md +++ b/packages/abi-gen/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/assert/CHANGELOG.json b/packages/assert/CHANGELOG.json index e2231a6769..a53339d3db 100644 --- a/packages/assert/CHANGELOG.json +++ b/packages/assert/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.2", "changes": [ diff --git a/packages/assert/CHANGELOG.md b/packages/assert/CHANGELOG.md index 6821154976..f865b86c19 100644 --- a/packages/assert/CHANGELOG.md +++ b/packages/assert/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json index 80b02f2c6d..82e072dde2 100644 --- a/packages/asset-buyer/CHANGELOG.json +++ b/packages/asset-buyer/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "5.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "5.0.3", "changes": [ diff --git a/packages/asset-buyer/CHANGELOG.md b/packages/asset-buyer/CHANGELOG.md index c5977e3e49..6f268f8835 100644 --- a/packages/asset-buyer/CHANGELOG.md +++ b/packages/asset-buyer/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v5.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v5.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index d3cf766964..e3a3992c15 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "4.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "4.0.2", "changes": [ diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md index 68de790bc2..ffc1f670bd 100644 --- a/packages/base-contract/CHANGELOG.md +++ b/packages/base-contract/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v4.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json index d7e557146e..aca42a092e 100644 --- a/packages/connect/CHANGELOG.json +++ b/packages/connect/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "4.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "4.0.3", "changes": [ diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md index 3094d22516..3fdd9ac025 100644 --- a/packages/connect/CHANGELOG.md +++ b/packages/connect/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v4.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 6e0d1ca4b4..1554f30f84 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Added calldata decoding to ContractWrappers", "pr": 1569 } - ] + ], + "timestamp": 1549733923 }, { "version": "7.0.2", diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md index 2e174e7673..c2ccbec49b 100644 --- a/packages/contract-wrappers/CHANGELOG.md +++ b/packages/contract-wrappers/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v7.1.0 - _February 9, 2019_ + + * Added calldata decoding to ContractWrappers (#1569) + ## v7.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/contracts-gen/CHANGELOG.json b/packages/contracts-gen/CHANGELOG.json index f1a523c304..3c1a26b5d8 100644 --- a/packages/contracts-gen/CHANGELOG.json +++ b/packages/contracts-gen/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "1.0.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.1", "changes": [ diff --git a/packages/contracts-gen/CHANGELOG.md b/packages/contracts-gen/CHANGELOG.md index e046c6a0a9..54cc2a6b96 100644 --- a/packages/contracts-gen/CHANGELOG.md +++ b/packages/contracts-gen/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.2 - _February 9, 2019_ + + * Dependencies updated + ## v1.0.1 - _February 7, 2019_ * Dependencies updated diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json index cbeb2e74f3..4684fa9155 100644 --- a/packages/dev-utils/CHANGELOG.json +++ b/packages/dev-utils/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Allow using the Web3Factory in-process Ganache provider with existing DB snapshot", "pr": 1602 } - ] + ], + "timestamp": 1549733923 }, { "version": "2.0.2", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 41e2ca88a3..084c336cc4 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.0 - _February 9, 2019_ + + * Allow using the Web3Factory in-process Ganache provider with existing DB snapshot (#1602) + ## v2.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index 8615d137b7..87503eba01 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/packages/fill-scenarios/CHANGELOG.md b/packages/fill-scenarios/CHANGELOG.md index e87652e7da..1e95eb171d 100644 --- a/packages/fill-scenarios/CHANGELOG.md +++ b/packages/fill-scenarios/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index a6ae0160f4..2be8ed069e 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "3.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.2", "changes": [ diff --git a/packages/json-schemas/CHANGELOG.md b/packages/json-schemas/CHANGELOG.md index 91426a6870..682a9c5fb5 100644 --- a/packages/json-schemas/CHANGELOG.md +++ b/packages/json-schemas/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v3.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json index 9d7c22b7c8..af1064d819 100644 --- a/packages/migrations/CHANGELOG.json +++ b/packages/migrations/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "3.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.3", "changes": [ diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md index b39732ef4a..7183eba692 100644 --- a/packages/migrations/CHANGELOG.md +++ b/packages/migrations/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v3.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 8f984538b5..26636d231f 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Updated implementation of `generatePseudoRandomSalt` to use generator from @0x/utils", "pr": 1569 } - ] + ], + "timestamp": 1549733923 }, { "version": "6.0.1", diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md index 06e6a28391..a661c0e1ff 100644 --- a/packages/order-utils/CHANGELOG.md +++ b/packages/order-utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v6.1.0 - _February 9, 2019_ + + * Updated implementation of `generatePseudoRandomSalt` to use generator from @0x/utils (#1569) + ## v6.0.1 - _February 7, 2019_ * Dependencies updated diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index 69bcc8d03e..31faf46385 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "3.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.3", "changes": [ diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md index 7a3ede421d..313ca96c7f 100644 --- a/packages/order-watcher/CHANGELOG.md +++ b/packages/order-watcher/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v3.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/react-docs/CHANGELOG.json b/packages/react-docs/CHANGELOG.json index 82e1622725..a14816bb8d 100644 --- a/packages/react-docs/CHANGELOG.json +++ b/packages/react-docs/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/packages/react-docs/CHANGELOG.md b/packages/react-docs/CHANGELOG.md index fa8f387c2c..ef3b50a9b9 100644 --- a/packages/react-docs/CHANGELOG.md +++ b/packages/react-docs/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json index 9a7284c2a0..97a9fc0d28 100644 --- a/packages/react-shared/CHANGELOG.json +++ b/packages/react-shared/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/packages/react-shared/CHANGELOG.md b/packages/react-shared/CHANGELOG.md index e1de4a7658..4b987be9f8 100644 --- a/packages/react-shared/CHANGELOG.md +++ b/packages/react-shared/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json index ed9c45245f..66c533696c 100644 --- a/packages/sol-compiler/CHANGELOG.json +++ b/packages/sol-compiler/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "3.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.2", "changes": [ diff --git a/packages/sol-compiler/CHANGELOG.md b/packages/sol-compiler/CHANGELOG.md index 0165090286..f054773eff 100644 --- a/packages/sol-compiler/CHANGELOG.md +++ b/packages/sol-compiler/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v3.0.2 - _February 7, 2019_ * Fix a bug when smart recompilation wasn't working because of remappings (#1575) diff --git a/packages/sol-coverage/CHANGELOG.json b/packages/sol-coverage/CHANGELOG.json index dc5ae1a53a..60ea58be75 100644 --- a/packages/sol-coverage/CHANGELOG.json +++ b/packages/sol-coverage/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.2", "changes": [ diff --git a/packages/sol-coverage/CHANGELOG.md b/packages/sol-coverage/CHANGELOG.md index 1af9b9f26e..90d45a88b1 100644 --- a/packages/sol-coverage/CHANGELOG.md +++ b/packages/sol-coverage/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/sol-doc/CHANGELOG.json b/packages/sol-doc/CHANGELOG.json index d9d0ddfa28..790977248f 100644 --- a/packages/sol-doc/CHANGELOG.json +++ b/packages/sol-doc/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.2", "changes": [ diff --git a/packages/sol-doc/CHANGELOG.md b/packages/sol-doc/CHANGELOG.md index 06ea1d7b42..da53808c14 100644 --- a/packages/sol-doc/CHANGELOG.md +++ b/packages/sol-doc/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/sol-profiler/CHANGELOG.json b/packages/sol-profiler/CHANGELOG.json index 89f3f71719..f9306fc663 100644 --- a/packages/sol-profiler/CHANGELOG.json +++ b/packages/sol-profiler/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/packages/sol-profiler/CHANGELOG.md b/packages/sol-profiler/CHANGELOG.md index bf9e59e54f..49dcdb4f38 100644 --- a/packages/sol-profiler/CHANGELOG.md +++ b/packages/sol-profiler/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/sol-trace/CHANGELOG.json b/packages/sol-trace/CHANGELOG.json index c786a56a3b..c2e70a2cef 100644 --- a/packages/sol-trace/CHANGELOG.json +++ b/packages/sol-trace/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.3", "changes": [ diff --git a/packages/sol-trace/CHANGELOG.md b/packages/sol-trace/CHANGELOG.md index bcb75c423a..b413385847 100644 --- a/packages/sol-trace/CHANGELOG.md +++ b/packages/sol-trace/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index 911cf6c1ff..cbc1b41d5c 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "6.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "6.0.2", "changes": [ diff --git a/packages/sol-tracing-utils/CHANGELOG.md b/packages/sol-tracing-utils/CHANGELOG.md index 6f9fa5615a..a9eadc1918 100644 --- a/packages/sol-tracing-utils/CHANGELOG.md +++ b/packages/sol-tracing-utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v6.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v6.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/sra-spec/CHANGELOG.json b/packages/sra-spec/CHANGELOG.json index 05ea492439..417e2a5a24 100644 --- a/packages/sra-spec/CHANGELOG.json +++ b/packages/sra-spec/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.2", "changes": [ diff --git a/packages/sra-spec/CHANGELOG.md b/packages/sra-spec/CHANGELOG.md index ce7a097081..85fe23b490 100644 --- a/packages/sra-spec/CHANGELOG.md +++ b/packages/sra-spec/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v2.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json index 3d5bade1f4..1ca3ef9134 100644 --- a/packages/subproviders/CHANGELOG.json +++ b/packages/subproviders/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1549733923, + "version": "3.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.2", "changes": [ diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index b3dfa757ad..60dbaeafc7 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.3 - _February 9, 2019_ + + * Dependencies updated + ## v3.0.2 - _February 7, 2019_ * Dependencies updated diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index 95f61a43c7..2ff0d81038 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Added method decoding to AbiDecoder", "pr": 1569 } - ] + ], + "timestamp": 1549733923 }, { "version": "4.0.4", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 4772bbb865..772b6e5821 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.1.0 - _February 9, 2019_ + + * Added method decoding to AbiDecoder (#1569) + +## v4.0.4 - _Invalid date_ + + * Cleaner signature parsing (#1592) + ## v4.0.3 - _February 7, 2019_ * Dependencies updated diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index bf1dedc00f..a65e40e956 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Export `DecodedCalldata` from @0x/utils", "pr": 1569 } - ] + ], + "timestamp": 1549733923 }, { "version": "4.0.2", diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md index 461d55a262..bf0a98ca94 100644 --- a/packages/web3-wrapper/CHANGELOG.md +++ b/packages/web3-wrapper/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v5.0.0 - _February 9, 2019_ + + * Export `DecodedCalldata` from @0x/utils (#1569) + ## v4.0.2 - _February 7, 2019_ * Dependencies updated From e909faa3ef9cea5d9b4044b993251e98afdb0d19 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sat, 9 Feb 2019 18:44:40 +0000 Subject: [PATCH 38/39] Publish - 0x.js@5.0.0 - @0x/abi-gen@2.0.3 - @0x/abi-gen-wrappers@3.0.3 - @0x/assert@2.0.3 - @0x/asset-buyer@5.0.4 - @0x/base-contract@4.0.3 - @0x/connect@4.0.4 - @0x/contract-wrappers@7.1.0 - @0x/contracts-gen@1.0.2 - @0x/dev-tools-pages@0.0.19 - @0x/dev-utils@2.1.0 - @0x/fill-scenarios@2.0.4 - @0x/instant@1.0.13 - @0x/json-schemas@3.0.3 - @0x/metacoin@0.0.40 - @0x/migrations@3.0.4 - @0x/monorepo-scripts@1.0.24 - @0x/order-utils@6.1.0 - @0x/order-watcher@3.0.4 - @0x/pipeline@1.0.10 - @0x/react-docs@2.0.4 - @0x/react-shared@2.0.4 - @0x/sol-compiler@3.0.3 - @0x/sol-coverage@2.0.3 - @0x/sol-doc@2.0.3 - @0x/sol-profiler@2.0.4 - @0x/sol-trace@2.0.4 - @0x/sol-tracing-utils@6.0.3 - @0x/sra-spec@2.0.3 - @0x/subproviders@3.0.3 - @0x/testnet-faucets@1.0.69 - @0x/utils@4.1.0 - @0x/web3-wrapper@5.0.0 - @0x/website@0.0.72 - @0x/contracts-asset-proxy@1.0.5 - @0x/contracts-erc20@1.0.5 - @0x/contracts-erc721@1.0.5 - @0x/contracts-exchange@1.0.5 - @0x/contracts-exchange-forwarder@1.0.5 - @0x/contracts-exchange-libs@1.0.5 - @0x/contracts-extensions@2.0.4 - @0x/contracts-multisig@2.0.4 - @0x/contracts-test-utils@3.0.4 - @0x/contracts-utils@2.0.4 --- contracts/asset-proxy/package.json | 20 ++++++++--------- contracts/erc20/package.json | 18 ++++++++-------- contracts/erc721/package.json | 18 ++++++++-------- contracts/exchange-forwarder/package.json | 22 +++++++++---------- contracts/exchange-libs/package.json | 20 ++++++++--------- contracts/exchange/package.json | 20 ++++++++--------- contracts/extensions/package.json | 22 +++++++++---------- contracts/multisig/package.json | 18 ++++++++-------- contracts/test-utils/package.json | 22 +++++++++---------- contracts/utils/package.json | 20 ++++++++--------- packages/0x.js/package.json | 24 ++++++++++----------- packages/abi-gen-wrappers/package.json | 10 ++++----- packages/abi-gen/package.json | 4 ++-- packages/assert/package.json | 6 +++--- packages/asset-buyer/package.json | 18 ++++++++-------- packages/base-contract/package.json | 6 +++--- packages/connect/package.json | 10 ++++----- packages/contract-wrappers/package.json | 24 ++++++++++----------- packages/contracts-gen/package.json | 4 ++-- packages/dev-tools-pages/package.json | 4 ++-- packages/dev-utils/package.json | 8 +++---- packages/fill-scenarios/package.json | 12 +++++------ packages/instant/package.json | 16 +++++++------- packages/json-schemas/package.json | 4 ++-- packages/metacoin/package.json | 22 +++++++++---------- packages/migrations/package.json | 18 ++++++++-------- packages/monorepo-scripts/package.json | 4 ++-- packages/order-utils/package.json | 16 +++++++------- packages/order-watcher/package.json | 26 +++++++++++------------ packages/pipeline/package.json | 16 +++++++------- packages/react-docs/package.json | 8 +++---- packages/react-shared/package.json | 4 ++-- packages/sol-compiler/package.json | 12 +++++------ packages/sol-coverage/package.json | 6 +++--- packages/sol-doc/package.json | 6 +++--- packages/sol-profiler/package.json | 6 +++--- packages/sol-trace/package.json | 6 +++--- packages/sol-tracing-utils/package.json | 12 +++++------ packages/sra-spec/package.json | 4 ++-- packages/subproviders/package.json | 8 +++---- packages/testnet-faucets/package.json | 10 ++++----- packages/utils/package.json | 2 +- packages/web3-wrapper/package.json | 8 +++---- packages/website/package.json | 20 ++++++++--------- 44 files changed, 282 insertions(+), 282 deletions(-) diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index def8eead7b..067fa9d6a6 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-asset-proxy", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -46,10 +46,10 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contracts-gen": "^1.0.2", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -66,16 +66,16 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-erc20": "1.0.2", "@0x/contracts-erc721": "1.0.2", - "@0x/contracts-test-utils": "^3.0.3", + "@0x/contracts-test-utils": "^3.0.4", "@0x/contracts-utils": "2.0.1", - "@0x/order-utils": "^6.0.1", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index 45272f157e..dff121ae35 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-erc20", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -46,11 +46,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -67,13 +67,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-exchange-libs": "1.0.2", "@0x/contracts-utils": "2.0.1", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/contracts/erc721/package.json b/contracts/erc721/package.json index 830ea5d737..58eb068c35 100644 --- a/contracts/erc721/package.json +++ b/contracts/erc721/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-erc721", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -46,11 +46,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -67,12 +67,12 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-utils": "2.0.1", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/contracts/exchange-forwarder/package.json b/contracts/exchange-forwarder/package.json index 875d60ae68..3af027f6df 100644 --- a/contracts/exchange-forwarder/package.json +++ b/contracts/exchange-forwarder/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-exchange-forwarder", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -46,12 +46,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contract-wrappers": "^7.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contract-wrappers": "^7.1.0", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -68,18 +68,18 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-asset-proxy": "1.0.2", "@0x/contracts-erc20": "1.0.2", "@0x/contracts-erc721": "1.0.2", "@0x/contracts-exchange": "1.0.2", "@0x/contracts-exchange-libs": "1.0.2", "@0x/contracts-utils": "2.0.1", - "@0x/order-utils": "^6.0.1", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/contracts/exchange-libs/package.json b/contracts/exchange-libs/package.json index 8ffd5e81db..640458041c 100644 --- a/contracts/exchange-libs/package.json +++ b/contracts/exchange-libs/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-exchange-libs", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -46,11 +46,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -67,13 +67,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-utils": "2.0.1", - "@0x/order-utils": "^6.0.1", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/contracts/exchange/package.json b/contracts/exchange/package.json index b167850879..af29482ef4 100644 --- a/contracts/exchange/package.json +++ b/contracts/exchange/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-exchange", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -46,11 +46,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -67,17 +67,17 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-asset-proxy": "1.0.2", "@0x/contracts-erc20": "1.0.2", "@0x/contracts-erc721": "1.0.2", "@0x/contracts-exchange-libs": "1.0.2", "@0x/contracts-utils": "2.0.1", - "@0x/order-utils": "^6.0.1", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11" diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json index 831a3398a8..deeed7b9cf 100644 --- a/contracts/extensions/package.json +++ b/contracts/extensions/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-extensions", - "version": "2.0.3", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -46,12 +46,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contract-wrappers": "^7.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contract-wrappers": "^7.1.0", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -68,18 +68,18 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-asset-proxy": "1.0.2", "@0x/contracts-erc20": "1.0.2", "@0x/contracts-erc721": "1.0.2", "@0x/contracts-exchange": "1.0.2", "@0x/contracts-exchange-libs": "1.0.2", "@0x/contracts-utils": "2.0.1", - "@0x/order-utils": "^6.0.1", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/contracts/multisig/package.json b/contracts/multisig/package.json index f3774c4092..4df55e5953 100644 --- a/contracts/multisig/package.json +++ b/contracts/multisig/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-multisig", - "version": "2.0.3", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -46,11 +46,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/multisig/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/node": "*", @@ -67,13 +67,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", + "@0x/base-contract": "^4.0.3", "@0x/contracts-asset-proxy": "1.0.2", "@0x/contracts-erc20": "1.0.2", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/contracts/test-utils/package.json b/contracts/test-utils/package.json index b379f470a8..0e42bee0af 100644 --- a/contracts/test-utils/package.json +++ b/contracts/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-test-utils", - "version": "3.0.3", + "version": "3.0.4", "engines": { "node": ">=6.12" }, @@ -40,19 +40,19 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/dev-utils": "^2.0.2", - "@0x/order-utils": "^6.0.1", - "@0x/sol-compiler": "^3.0.2", - "@0x/sol-coverage": "^2.0.2", - "@0x/sol-profiler": "^2.0.3", - "@0x/sol-trace": "^2.0.3", - "@0x/subproviders": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/dev-utils": "^2.1.0", + "@0x/order-utils": "^6.1.0", + "@0x/sol-compiler": "^3.0.3", + "@0x/sol-coverage": "^2.0.3", + "@0x/sol-profiler": "^2.0.4", + "@0x/sol-trace": "^2.0.4", + "@0x/subproviders": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/bn.js": "^4.11.0", "@types/js-combinatorics": "^0.5.29", "@types/lodash": "4.14.104", diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 91abc8043e..13a3bc80bf 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-utils", - "version": "2.0.3", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -46,11 +46,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/utils/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", - "@0x/contracts-gen": "^1.0.1", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/abi-gen": "^2.0.3", + "@0x/contracts-gen": "^1.0.2", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", @@ -68,12 +68,12 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^4.0.2", - "@0x/order-utils": "^6.0.1", + "@0x/base-contract": "^4.0.3", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "bn.js": "^4.11.8", "ethereum-types": "^2.0.0", "ethereumjs-util": "^5.1.1", diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index b021768116..639bbf3510 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -1,6 +1,6 @@ { "name": "0x.js", - "version": "4.0.3", + "version": "5.0.0", "engines": { "node": ">=6.12" }, @@ -42,10 +42,10 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0x/abi-gen-wrappers": "^3.0.2", + "@0x/abi-gen-wrappers": "^3.0.3", "@0x/contract-addresses": "^2.2.1", - "@0x/dev-utils": "^2.0.2", - "@0x/migrations": "^3.0.3", + "@0x/dev-utils": "^2.1.0", + "@0x/migrations": "^3.0.4", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", @@ -72,16 +72,16 @@ "webpack": "^4.20.2" }, "dependencies": { - "@0x/assert": "^2.0.2", - "@0x/base-contract": "^4.0.2", - "@0x/contract-wrappers": "^7.0.2", - "@0x/order-utils": "^6.0.1", - "@0x/order-watcher": "^3.0.3", - "@0x/subproviders": "^3.0.2", + "@0x/assert": "^2.0.3", + "@0x/base-contract": "^4.0.3", + "@0x/contract-wrappers": "^7.1.0", + "@0x/order-utils": "^6.1.0", + "@0x/order-watcher": "^3.0.4", + "@0x/subproviders": "^3.0.3", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/web3-provider-engine": "^14.0.0", "ethereum-types": "^2.0.0", "ethers": "~4.0.4", diff --git a/packages/abi-gen-wrappers/package.json b/packages/abi-gen-wrappers/package.json index c9682e28fc..ff65f7e030 100644 --- a/packages/abi-gen-wrappers/package.json +++ b/packages/abi-gen-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0x/abi-gen-wrappers", - "version": "3.0.2", + "version": "3.0.3", "engines": { "node": ">=6.12" }, @@ -30,19 +30,19 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md", "devDependencies": { - "@0x/abi-gen": "^2.0.2", + "@0x/abi-gen": "^2.0.3", "@0x/abi-gen-templates": "^2.0.0", "@0x/tslint-config": "^3.0.0", "@0x/types": "^2.0.2", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "ethers": "~4.0.4", "lodash": "^4.17.11", "shx": "^0.2.2" }, "dependencies": { - "@0x/base-contract": "^4.0.2" + "@0x/base-contract": "^4.0.3" }, "publishConfig": { "access": "public" diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index d07e0a5809..29433a68b3 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -1,6 +1,6 @@ { "name": "@0x/abi-gen", - "version": "2.0.2", + "version": "2.0.3", "engines": { "node": ">=6.12" }, @@ -32,7 +32,7 @@ "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md", "dependencies": { "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "chalk": "^2.3.0", "ethereum-types": "^2.0.0", "glob": "^7.1.2", diff --git a/packages/assert/package.json b/packages/assert/package.json index 551414de33..04061683c0 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -1,6 +1,6 @@ { "name": "@0x/assert", - "version": "2.0.2", + "version": "2.0.3", "engines": { "node": ">=6.12" }, @@ -44,9 +44,9 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/json-schemas": "^3.0.2", + "@0x/json-schemas": "^3.0.3", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "lodash": "^4.17.11", "valid-url": "^1.0.9" }, diff --git a/packages/asset-buyer/package.json b/packages/asset-buyer/package.json index 391a5d6881..a7e17441c7 100644 --- a/packages/asset-buyer/package.json +++ b/packages/asset-buyer/package.json @@ -1,6 +1,6 @@ { "name": "@0x/asset-buyer", - "version": "5.0.3", + "version": "5.0.4", "engines": { "node": ">=6.12" }, @@ -36,16 +36,16 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md", "dependencies": { - "@0x/assert": "^2.0.2", - "@0x/connect": "^4.0.3", - "@0x/contract-wrappers": "^7.0.2", - "@0x/json-schemas": "^3.0.2", - "@0x/order-utils": "^6.0.1", - "@0x/subproviders": "^3.0.2", + "@0x/assert": "^2.0.3", + "@0x/connect": "^4.0.4", + "@0x/contract-wrappers": "^7.1.0", + "@0x/json-schemas": "^3.0.3", + "@0x/order-utils": "^6.1.0", + "@0x/subproviders": "^3.0.3", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" }, diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index d9970b7f42..a1b9a08374 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -1,6 +1,6 @@ { "name": "@0x/base-contract", - "version": "4.0.2", + "version": "4.0.3", "engines": { "node": ">=6.12" }, @@ -41,8 +41,8 @@ }, "dependencies": { "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "ethers": "~4.0.4", "lodash": "^4.17.11" diff --git a/packages/connect/package.json b/packages/connect/package.json index a9648594c6..62a49c072f 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -1,6 +1,6 @@ { "name": "@0x/connect", - "version": "4.0.3", + "version": "4.0.4", "engines": { "node": ">=6.12" }, @@ -44,12 +44,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md", "dependencies": { - "@0x/assert": "^2.0.2", - "@0x/json-schemas": "^3.0.2", - "@0x/order-utils": "^6.0.1", + "@0x/assert": "^2.0.3", + "@0x/json-schemas": "^3.0.3", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "lodash": "^4.17.11", "query-string": "^6.0.0", "sinon": "^4.0.0", diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 7ea270eb55..b3fa98e41a 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contract-wrappers", - "version": "7.0.2", + "version": "7.1.0", "description": "Smart TS wrappers for 0x smart contracts", "keywords": [ "0xproject", @@ -37,9 +37,9 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0x/dev-utils": "^2.0.2", - "@0x/migrations": "^3.0.3", - "@0x/subproviders": "^3.0.2", + "@0x/dev-utils": "^2.1.0", + "@0x/migrations": "^3.0.4", + "@0x/subproviders": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", @@ -65,18 +65,18 @@ "web3-provider-engine": "14.0.6" }, "dependencies": { - "@0x/abi-gen-wrappers": "^3.0.2", - "@0x/assert": "^2.0.2", + "@0x/abi-gen-wrappers": "^3.0.3", + "@0x/assert": "^2.0.3", "@0x/contract-addresses": "^2.2.1", "@0x/contract-artifacts": "^1.3.0", - "@0x/contracts-test-utils": "^3.0.3", - "@0x/fill-scenarios": "^2.0.3", - "@0x/json-schemas": "^3.0.2", - "@0x/order-utils": "^6.0.1", + "@0x/contracts-test-utils": "^3.0.4", + "@0x/fill-scenarios": "^2.0.4", + "@0x/json-schemas": "^3.0.3", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "ethereumjs-abi": "0.6.5", "ethereumjs-blockstream": "6.0.0", diff --git a/packages/contracts-gen/package.json b/packages/contracts-gen/package.json index fdf22ab454..67d29083d5 100644 --- a/packages/contracts-gen/package.json +++ b/packages/contracts-gen/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-gen", - "version": "1.0.1", + "version": "1.0.2", "engines": { "node": ">=6.12" }, @@ -29,7 +29,7 @@ "@0x/sol-resolver": "^2.0.2", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11", "prettier": "^1.16.3", diff --git a/packages/dev-tools-pages/package.json b/packages/dev-tools-pages/package.json index 80ff16a441..17a0a1d77e 100644 --- a/packages/dev-tools-pages/package.json +++ b/packages/dev-tools-pages/package.json @@ -1,6 +1,6 @@ { "name": "@0x/dev-tools-pages", - "version": "0.0.18", + "version": "0.0.19", "engines": { "node": ">=6.12" }, @@ -26,7 +26,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@0x/react-shared": "^2.0.3", + "@0x/react-shared": "^2.0.4", "basscss": "^8.0.3", "bowser": "^1.9.3", "highlight.js": "^9.13.1", diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 89298f4dbf..ceae090350 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/dev-utils", - "version": "2.0.2", + "version": "2.1.0", "engines": { "node": ">=6.12" }, @@ -41,11 +41,11 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/subproviders": "^3.0.2", + "@0x/subproviders": "^3.0.3", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/web3-provider-engine": "^14.0.0", "chai": "^4.0.1", "ethereum-types": "^2.0.0", diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index 523bc07c12..fb468deb73 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -1,6 +1,6 @@ { "name": "@0x/fill-scenarios", - "version": "2.0.3", + "version": "2.0.4", "description": "0x order fill scenario generator", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -28,14 +28,14 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^3.0.2", - "@0x/base-contract": "^4.0.2", + "@0x/abi-gen-wrappers": "^3.0.3", + "@0x/base-contract": "^4.0.3", "@0x/contract-artifacts": "^1.3.0", - "@0x/order-utils": "^6.0.1", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "ethereum-types": "^2.0.0", "ethers": "~4.0.4", "lodash": "^4.17.11" diff --git a/packages/instant/package.json b/packages/instant/package.json index 0fe45e9632..81fc61ec58 100644 --- a/packages/instant/package.json +++ b/packages/instant/package.json @@ -1,6 +1,6 @@ { "name": "@0x/instant", - "version": "1.0.12", + "version": "1.0.13", "engines": { "node": ">=6.12" }, @@ -42,15 +42,15 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md", "dependencies": { - "@0x/assert": "^2.0.2", - "@0x/asset-buyer": "^5.0.3", - "@0x/json-schemas": "^3.0.2", - "@0x/order-utils": "^6.0.1", - "@0x/subproviders": "^3.0.2", + "@0x/assert": "^2.0.3", + "@0x/asset-buyer": "^5.0.4", + "@0x/json-schemas": "^3.0.3", + "@0x/order-utils": "^6.1.0", + "@0x/subproviders": "^3.0.3", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "babel-runtime": "^6.26.0", "bowser": "^1.9.4", "copy-to-clipboard": "^3.0.8", diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index 0c101aa285..189b06e749 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@0x/json-schemas", - "version": "3.0.2", + "version": "3.0.3", "engines": { "node": ">=6.12" }, @@ -46,7 +46,7 @@ }, "devDependencies": { "@0x/tslint-config": "^3.0.0", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "@types/lodash.foreach": "^4.5.3", "@types/lodash.values": "^4.3.3", "@types/mocha": "^2.2.42", diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 3afe8eb8c8..83c3821e0f 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -1,6 +1,6 @@ { "name": "@0x/metacoin", - "version": "0.0.39", + "version": "0.0.40", "engines": { "node": ">=6.12" }, @@ -30,18 +30,18 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "@0x/abi-gen": "^2.0.2", + "@0x/abi-gen": "^2.0.3", "@0x/abi-gen-templates": "^2.0.0", - "@0x/base-contract": "^4.0.2", - "@0x/sol-coverage": "^2.0.2", - "@0x/sol-profiler": "^2.0.3", - "@0x/sol-trace": "^2.0.3", - "@0x/subproviders": "^3.0.2", + "@0x/base-contract": "^4.0.3", + "@0x/sol-coverage": "^2.0.3", + "@0x/sol-profiler": "^2.0.4", + "@0x/sol-trace": "^2.0.4", + "@0x/subproviders": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/mocha": "^2.2.42", "copyfiles": "^2.0.0", "ethereum-types": "^2.0.0", @@ -50,8 +50,8 @@ "run-s": "^0.0.0" }, "devDependencies": { - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", diff --git a/packages/migrations/package.json b/packages/migrations/package.json index 91476d322d..727db9096b 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -1,6 +1,6 @@ { "name": "@0x/migrations", - "version": "3.0.3", + "version": "3.0.4", "engines": { "node": ">=6.12" }, @@ -35,7 +35,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0x/dev-utils": "^2.0.2", + "@0x/dev-utils": "^2.1.0", "@0x/tslint-config": "^3.0.0", "@0x/types": "^2.0.2", "@types/yargs": "^11.0.0", @@ -48,16 +48,16 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0x/abi-gen-wrappers": "^3.0.2", - "@0x/base-contract": "^4.0.2", + "@0x/abi-gen-wrappers": "^3.0.3", + "@0x/base-contract": "^4.0.3", "@0x/contract-addresses": "^2.2.1", "@0x/contract-artifacts": "^1.3.0", - "@0x/order-utils": "^6.0.1", - "@0x/sol-compiler": "^3.0.2", - "@0x/subproviders": "^3.0.2", + "@0x/order-utils": "^6.1.0", + "@0x/sol-compiler": "^3.0.3", + "@0x/subproviders": "^3.0.3", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@ledgerhq/hw-app-eth": "^4.3.0", "ethereum-types": "^2.0.0", "ethers": "~4.0.4", diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index 3e9a972c22..ee7f5968be 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0x/monorepo-scripts", - "version": "1.0.23", + "version": "1.0.24", "engines": { "node": ">=6.12" }, @@ -48,7 +48,7 @@ }, "dependencies": { "@0x/types": "^2.0.2", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "@lerna/batch-packages": "^3.0.0-beta.18", "@types/depcheck": "^0.6.0", "async-child-process": "^1.1.1", diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index e2d0bcc980..df0e7a38f4 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/order-utils", - "version": "6.0.1", + "version": "6.1.0", "engines": { "node": ">=6.12" }, @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md", "devDependencies": { - "@0x/dev-utils": "^2.0.2", + "@0x/dev-utils": "^2.1.0", "@0x/tslint-config": "^3.0.0", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", @@ -53,16 +53,16 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^3.0.2", - "@0x/assert": "^2.0.2", - "@0x/base-contract": "^4.0.2", + "@0x/abi-gen-wrappers": "^3.0.3", + "@0x/assert": "^2.0.3", + "@0x/base-contract": "^4.0.3", "@0x/contract-addresses": "^2.2.1", "@0x/contract-artifacts": "^1.3.0", - "@0x/json-schemas": "^3.0.2", + "@0x/json-schemas": "^3.0.3", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/node": "*", "bn.js": "^4.11.8", "ethereum-types": "^2.0.0", diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index 209c9bdc5f..368bb879db 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -1,6 +1,6 @@ { "name": "@0x/order-watcher", - "version": "3.0.3", + "version": "3.0.4", "description": "An order watcher daemon that watches for order validity", "keywords": [ "0x", @@ -38,9 +38,9 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0x/dev-utils": "^2.0.2", - "@0x/migrations": "^3.0.3", - "@0x/subproviders": "^3.0.2", + "@0x/dev-utils": "^2.1.0", + "@0x/migrations": "^3.0.4", + "@0x/subproviders": "^3.0.3", "@0x/tslint-config": "^3.0.0", "@types/bintrees": "^1.0.2", "@types/lodash": "4.14.104", @@ -63,19 +63,19 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^3.0.2", - "@0x/assert": "^2.0.2", - "@0x/base-contract": "^4.0.2", + "@0x/abi-gen-wrappers": "^3.0.3", + "@0x/assert": "^2.0.3", + "@0x/base-contract": "^4.0.3", "@0x/contract-addresses": "^2.2.1", "@0x/contract-artifacts": "^1.3.0", - "@0x/contract-wrappers": "^7.0.2", - "@0x/fill-scenarios": "^2.0.3", - "@0x/json-schemas": "^3.0.2", - "@0x/order-utils": "^6.0.1", + "@0x/contract-wrappers": "^7.1.0", + "@0x/fill-scenarios": "^2.0.4", + "@0x/json-schemas": "^3.0.3", + "@0x/order-utils": "^6.1.0", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "bintrees": "^1.0.2", "ethereum-types": "^2.0.0", "ethereumjs-blockstream": "6.0.0", diff --git a/packages/pipeline/package.json b/packages/pipeline/package.json index b2ad39a5f2..56d5ef10d9 100644 --- a/packages/pipeline/package.json +++ b/packages/pipeline/package.json @@ -1,6 +1,6 @@ { "name": "@0x/pipeline", - "version": "1.0.9", + "version": "1.0.10", "private": true, "description": "Data pipeline for offline analysis", "scripts": { @@ -39,16 +39,16 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/connect": "^4.0.3", + "@0x/connect": "^4.0.4", "@0x/contract-addresses": "^2.2.1", "@0x/contract-artifacts": "^1.3.0", - "@0x/contract-wrappers": "^7.0.2", - "@0x/dev-utils": "^2.0.2", - "@0x/order-utils": "^6.0.1", - "@0x/subproviders": "^3.0.2", + "@0x/contract-wrappers": "^7.1.0", + "@0x/dev-utils": "^2.1.0", + "@0x/order-utils": "^6.1.0", + "@0x/subproviders": "^3.0.3", "@0x/types": "^2.0.2", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/dockerode": "^2.5.9", "@types/p-limit": "^2.0.0", "async-parallel": "^1.2.3", diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index 5a91220e01..e3da83909c 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -1,6 +1,6 @@ { "name": "@0x/react-docs", - "version": "2.0.3", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -24,7 +24,7 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0x/dev-utils": "^2.0.2", + "@0x/dev-utils": "^2.1.0", "@0x/tslint-config": "^3.0.0", "@types/compare-versions": "^3.0.0", "@types/styled-components": "4.0.0", @@ -34,9 +34,9 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/react-shared": "^2.0.3", + "@0x/react-shared": "^2.0.4", "@0x/types": "^2.0.2", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "@types/lodash": "4.14.104", "@types/material-ui": "^0.20.0", "@types/node": "*", diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index d93eb14367..141f3c1956 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -1,6 +1,6 @@ { "name": "@0x/react-shared", - "version": "2.0.3", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -25,7 +25,7 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0x/dev-utils": "^2.0.2", + "@0x/dev-utils": "^2.1.0", "@0x/tslint-config": "^3.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index 3344c0b381..6629c02e91 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-compiler", - "version": "3.0.2", + "version": "3.0.3", "engines": { "node": ">=6.12" }, @@ -42,7 +42,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-compiler/README.md", "devDependencies": { - "@0x/dev-utils": "^2.0.2", + "@0x/dev-utils": "^2.1.0", "@0x/tslint-config": "^3.0.0", "@types/chokidar": "^1.7.5", "@types/mkdirp": "^0.5.2", @@ -67,13 +67,13 @@ "zeppelin-solidity": "1.8.0" }, "dependencies": { - "@0x/assert": "^2.0.2", - "@0x/json-schemas": "^3.0.2", + "@0x/assert": "^2.0.3", + "@0x/json-schemas": "^3.0.3", "@0x/sol-resolver": "^2.0.2", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/yargs": "^11.0.0", "chalk": "^2.3.0", "chokidar": "^2.0.4", diff --git a/packages/sol-coverage/package.json b/packages/sol-coverage/package.json index 6724a03dfc..8bc91f63c2 100644 --- a/packages/sol-coverage/package.json +++ b/packages/sol-coverage/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-coverage", - "version": "2.0.2", + "version": "2.0.3", "engines": { "node": ">=6.12" }, @@ -29,8 +29,8 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-coverage/README.md", "dependencies": { - "@0x/sol-tracing-utils": "^6.0.2", - "@0x/subproviders": "^3.0.2", + "@0x/sol-tracing-utils": "^6.0.3", + "@0x/subproviders": "^3.0.3", "@0x/typescript-typings": "^4.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" diff --git a/packages/sol-doc/package.json b/packages/sol-doc/package.json index c413e248f3..0a1d21685c 100644 --- a/packages/sol-doc/package.json +++ b/packages/sol-doc/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-doc", - "version": "2.0.2", + "version": "2.0.3", "description": "Solidity documentation generator", "main": "lib/src/index.js", "types": "lib/src/index.d.js", @@ -25,9 +25,9 @@ "author": "F. Eugene Aumson", "license": "Apache-2.0", "dependencies": { - "@0x/sol-compiler": "^3.0.2", + "@0x/sol-compiler": "^3.0.3", "@0x/types": "^2.0.2", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "ethereum-types": "^2.0.0", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11", diff --git a/packages/sol-profiler/package.json b/packages/sol-profiler/package.json index cce49e22ea..c28d3207a9 100644 --- a/packages/sol-profiler/package.json +++ b/packages/sol-profiler/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-profiler", - "version": "2.0.3", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -29,8 +29,8 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-profiler/README.md", "dependencies": { - "@0x/sol-tracing-utils": "^6.0.2", - "@0x/subproviders": "^3.0.2", + "@0x/sol-tracing-utils": "^6.0.3", + "@0x/subproviders": "^3.0.3", "@0x/typescript-typings": "^4.0.0", "ethereum-types": "^2.0.0", "lodash": "^4.17.11" diff --git a/packages/sol-trace/package.json b/packages/sol-trace/package.json index b65a8b002d..6dc3a230ed 100644 --- a/packages/sol-trace/package.json +++ b/packages/sol-trace/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-trace", - "version": "2.0.3", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -29,8 +29,8 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-trace/README.md", "dependencies": { - "@0x/sol-tracing-utils": "^6.0.2", - "@0x/subproviders": "^3.0.2", + "@0x/sol-tracing-utils": "^6.0.3", + "@0x/subproviders": "^3.0.3", "@0x/typescript-typings": "^4.0.0", "chalk": "^2.3.0", "ethereum-types": "^2.0.0", diff --git a/packages/sol-tracing-utils/package.json b/packages/sol-tracing-utils/package.json index 8bccb237d7..4d22107f32 100644 --- a/packages/sol-tracing-utils/package.json +++ b/packages/sol-tracing-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-tracing-utils", - "version": "6.0.2", + "version": "6.0.3", "engines": { "node": ">=6.12" }, @@ -42,13 +42,13 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-tracing-utils/README.md", "dependencies": { - "@0x/dev-utils": "^2.0.2", - "@0x/sol-compiler": "^3.0.2", + "@0x/dev-utils": "^2.1.0", + "@0x/sol-compiler": "^3.0.3", "@0x/sol-resolver": "^2.0.2", - "@0x/subproviders": "^3.0.2", + "@0x/subproviders": "^3.0.3", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@types/solidity-parser-antlr": "^0.2.0", "chalk": "^2.3.0", "ethereum-types": "^2.0.0", diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index 28cf159380..b685432d4c 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sra-spec", - "version": "2.0.2", + "version": "2.0.3", "engines": { "node": ">=6.12" }, @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-spec/README.md", "dependencies": { - "@0x/json-schemas": "^3.0.2", + "@0x/json-schemas": "^3.0.3", "@loopback/openapi-v3-types": "^0.8.2" }, "devDependencies": { diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index a783bb5a22..66a09000c1 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,6 +1,6 @@ { "name": "@0x/subproviders", - "version": "3.0.2", + "version": "3.0.3", "engines": { "node": ">=6.12" }, @@ -29,11 +29,11 @@ } }, "dependencies": { - "@0x/assert": "^2.0.2", + "@0x/assert": "^2.0.3", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@ledgerhq/hw-app-eth": "^4.3.0", "@ledgerhq/hw-transport-u2f": "4.24.0", "@types/eth-lightwallet": "^3.0.0", diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index c529d4975a..31bfc6e1d6 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0x/testnet-faucets", - "version": "1.0.68", + "version": "1.0.69", "engines": { "node": ">=6.12" }, @@ -18,11 +18,11 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "0x.js": "^4.0.3", - "@0x/subproviders": "^3.0.2", + "0x.js": "^5.0.0", + "@0x/subproviders": "^3.0.3", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "body-parser": "^1.17.1", "ethereum-types": "^2.0.0", "ethereumjs-tx": "^1.3.5", diff --git a/packages/utils/package.json b/packages/utils/package.json index 895560961f..48b98173d2 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/utils", - "version": "4.0.3", + "version": "4.1.0", "engines": { "node": ">=6.12" }, diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index d28a9894ff..d6f0bf90d0 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -1,6 +1,6 @@ { "name": "@0x/web3-wrapper", - "version": "4.0.2", + "version": "5.0.0", "engines": { "node": ">=6.12" }, @@ -54,10 +54,10 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/assert": "^2.0.2", - "@0x/json-schemas": "^3.0.2", + "@0x/assert": "^2.0.3", + "@0x/json-schemas": "^3.0.3", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", + "@0x/utils": "^4.1.0", "ethereum-types": "^2.0.0", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", diff --git a/packages/website/package.json b/packages/website/package.json index 165ce57251..7fc9b4660d 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "@0x/website", - "version": "0.0.71", + "version": "0.0.72", "engines": { "node": ">=6.12" }, @@ -20,18 +20,18 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "@0x/asset-buyer": "^5.0.3", + "@0x/asset-buyer": "^5.0.4", "@0x/contract-addresses": "^2.2.1", - "@0x/contract-wrappers": "^7.0.2", - "@0x/json-schemas": "^3.0.2", - "@0x/order-utils": "^6.0.1", - "@0x/react-docs": "^2.0.3", - "@0x/react-shared": "^2.0.3", - "@0x/subproviders": "^3.0.2", + "@0x/contract-wrappers": "^7.1.0", + "@0x/json-schemas": "^3.0.3", + "@0x/order-utils": "^6.1.0", + "@0x/react-docs": "^2.0.4", + "@0x/react-shared": "^2.0.4", + "@0x/subproviders": "^3.0.3", "@0x/types": "^2.0.2", "@0x/typescript-typings": "^4.0.0", - "@0x/utils": "^4.0.3", - "@0x/web3-wrapper": "^4.0.2", + "@0x/utils": "^4.1.0", + "@0x/web3-wrapper": "^5.0.0", "@reach/dialog": "^0.1.2", "@types/react-lazyload": "^2.3.1", "@types/react-loadable": "^5.4.2", From df896877f8d950f2e25186485ea653f9233bf8b3 Mon Sep 17 00:00:00 2001 From: David Sun Date: Tue, 12 Feb 2019 17:24:57 -0500 Subject: [PATCH 39/39] added forum link --- packages/website/ts/components/footer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx index 3765a32ca4..e6a7904a81 100644 --- a/packages/website/ts/components/footer.tsx +++ b/packages/website/ts/components/footer.tsx @@ -62,6 +62,7 @@ const linkRows: LinkRows[] = [ { url: constants.URL_ZEROEX_CHAT, text: 'Discord Chat', shouldOpenInNewTab: true }, { url: constants.URL_FACEBOOK, text: 'Facebook', shouldOpenInNewTab: true }, { url: constants.URL_REDDIT, text: 'Reddit', shouldOpenInNewTab: true }, + { url: constants.URL_FORUM, text: 'Forum', shouldOpenInNewTab: true }, ], }, ];