import BigNum = require ( 'bn.js' ) ; import * as assert from 'assert' ; export type Endianness = 'B' | 'L' ; export const BIG_ENDIAN = 'B' ; export const LITTLE_ENDIAN = 'L' ; /**
 * Class to represent big numbers in the codebase.
 * This is a façade, wrapping the underlying Big Number implementation so that we can
 * swap out implementations if necessary without breaking usages.
 */ export class BigNumber { private readonly num : BigNum ; constructor ( number , base ? , endian ? ) { const parsedNumber = number instanceof BigNumber ? number . num : number ; const endianness = ! ! endian ? this . getBigNumEndianness ( endian ) : undefined ; if ( ! ! base ) { this . num = new BigNum ( parsedNumber , base , endianness ) ; } else if ( ! ! endian ) { this . num = new BigNum ( parsedNumber , endianness ) ; } else { this . num = new BigNum ( parsedNumber ) ; } } param left param right public static min ( left , right ) { return new BigNumber ( BigNum . min ( left . num , right . num ) ) ; } param left param right public static max ( left , right ) { return new BigNumber ( BigNum . max ( left . num , right . num ) ) ; } param num returns public static isBigNumber ( num ) { if ( num instanceof BigNumber ) { return BigNum . isBN ( num . num ) ; } return false ; } /**
     * Creates a copy of `this` without the same memory reference.
     */ public clone ( ) { return new BigNumber ( this ) ; } param base param length returns public toString ( base = 'hex' , length ? ) { return length === undefined ? this . num . toString ( base ) : this . num . toString ( base , length ) ; } returns public toJSON ( ) { return this . toString ( 'hex' ) ; } returns public toNumber ( ) { return this . num . toNumber ( ) ; } param endian param length public toBuffer ( endian ? , length ? ) { if ( endian ) { const endianness = this . getBigNumEndianness ( endian ) ; if ( length ) { return this . num . toBuffer ( endianness , length ) ; } return this . num . toBuffer ( endianness ) ; } return this . num . toBuffer ( ) ; } /**************
     * Operations *
     **************/ param other returns public add ( other ) { return new BigNumber ( this . num . add ( other . num ) ) ; } param other returns public sub ( other ) { return new BigNumber ( this . num . sub ( other . num ) ) ; } param other returns public mul ( other ) { return new BigNumber ( this . num . mul ( other . num ) ) ; } param other returns public div ( other ) { return new BigNumber ( this . num . div ( other . num ) ) ; } param other returns public divRound ( other ) { const thisAbs = this . abs ( ) ; const otherAbs = other . abs ( ) ; const remainderAbs = thisAbs . mod ( otherAbs ) ; const div = this . div ( other ) ; if ( remainderAbs . eq ( ZERO ) ) { return div ; } const decimalAbs = remainderAbs . div ( otherAbs ) ; if ( decimalAbs . gte ( ONE_HALF ) ) { if ( div . num . isNeg ( ) ) { return div . add ( remainderAbs ) . sub ( ONE ) ; } else { return div . sub ( remainderAbs ) . add ( ONE ) ; } } else { if ( div . num . isNeg ( ) ) { return div . add ( remainderAbs ) ; } else { return div . sub ( remainderAbs ) ; } } } param other returns public pow ( exp ) { assert ( exp . mod ( ONE ) . eq ( ZERO ) , 'BigNumber.pow(...) does not support fractions at this time.' ) ; assert ( ! exp . num . isNeg ( ) , 'BigNumber.pow(...) does not support negative exponents at this time.' ) ; return new BigNumber ( this . num . pow ( exp . num ) ) ; } param other returns public mod ( mod ) { assert ( ! this . num . isNeg ( ) || ! mod . num . isNeg ( ) , 'Big number does not support negative mod negative.' ) ; return new BigNumber ( this . num . mod ( mod . num ) ) ; } param other returns public modNum ( mod ) { assert ( ! this . num . isNeg ( ) || mod >= 0 , 'Big number does not support negative mod negative.' ) ; return new BigNumber ( this . num . modn ( mod ) ) ; } /**
     * Returns the absolute value of this BigNumber as a *new* BigNumber.
     */ public abs ( ) { return new BigNumber ( this . num . abs ( ) ) ; } param num returns public xor ( num ) { return new BigNumber ( this . num . xor ( num . num ) ) ; } param num returns public and ( num ) { return new BigNumber ( this . num . and ( num . num ) ) ; } param num public shiftLeft ( num ) { return new BigNumber ( this . num . shln ( num ) ) ; } param num public shiftRight ( num ) { return new BigNumber ( this . num . shrn ( num ) ) ; } param num public shiftLeftInPlace ( num ) { this . num . ishln ( num ) ; return this ; } param num public shiftRightInPlace ( num ) { this . num . ishrn ( num ) ; return this ; } /***************
     * Comparisons *
     ***************/ param other returns public gt ( other ) { return this . num . gt ( other . num ) ; } param other returns public gte ( other ) { return this . num . gte ( other . num ) ; } param other returns public lt ( other ) { return this . num . lt ( other . num ) ; } param other returns public lte ( other ) { return this . num . lte ( other . num ) ; } param other returns public eq ( other ) { return this . num . eq ( other . num ) ; } /**
     * eq alias to comply with standard
     */ public equals ( other ) { return this . eq ( other ) ; } param other returns public compare ( other ) { return this . lt ( other ) ? - 1 : this . eq ( other ) ? 0 : 1 ; } param endianness returns private getBigNumEndianness ( endianness ) { if ( endianness === BIG_ENDIAN ) { return 'be' ; } else if ( endianness === LITTLE_ENDIAN ) { return 'le' ; } throw Error ( `Cannot get Endianness from ${ JSON . stringify ( endianness ) }` ) ; } } export const ZERO = new BigNumber ( 0 ) ; export const ONE = new BigNumber ( 1 ) ; export const TWO = new BigNumber ( 2 ) ; export const THREE = new BigNumber ( 3 ) ; export const ONE_HALF = new BigNumber ( 0.5 ) ; export const MAX_BIG_NUM = new BigNumber ( '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' ) ;