import { BinaryReader , InvalidFormatError , utils as clientUtils , WildcardContainerJSON } from '@neo-one/client-common' ; import BigNumber from 'bignumber.js' ; import { BN } from 'bn.js' ; import { randomBytes } from 'crypto' ; import _ from 'lodash' ; import { StackItem } from '../StackItems' ; import { StorageItem } from '../StorageItem' ; import { executionLimits } from '../vm' ; import { deserializeStackItem } from './deserializeStackItem' ; const toASCII = ( bytes ) => { let result = '' ; _ . range ( bytes . length ) . forEach ( ( i ) => { result += String . fromCharCode ( bytes . readUInt8 ( i ) ) ; } ) ; return result ; } ; const toUTF8 = ( bytes ) => bytes . toString ( 'utf8' ) ; const randomUInt64 = ( ) : BN => new BN ( randomBytes ( 8 ) . toString ( 'hex' ) , 16 ) ; const toKeyString = ( clazz , toKey ) => ( ) => `${ clazz . name }:${ toKey ( ) }` ; function lazyAsync < Input , Value > ( getValue ) { let valuePromise ; return async ( input ) => { if ( valuePromise === undefined ) { valuePromise = getValue ( input ) ; } return valuePromise ; } ; } function lazyOrValue < Value > ( getValue ) { let settings = typeof getValue === 'function' ? { type : 'lazy' , getValue } : { type : 'evaluated' , value : getValue } ; return ( ) => { if ( settings . type === 'lazy' ) { settings = { type : 'evaluated' , value : settings . getValue ( ) } ; } return settings . value ; } ; } function weightedAverage ( input ) { let sumWeight = new BigNumber ( 0 ) ; let sumValue = new BigNumber ( 0 ) ; input . forEach ( ( value ) => { sumWeight = sumWeight . plus ( value . weight ) ; sumValue = sumValue . plus ( value . weight . times ( value . value ) ) ; } ) ; if ( sumValue . isEqualTo ( 0 ) || sumWeight . isEqualTo ( 0 ) ) { return 0 ; } return sumValue . div ( sumWeight ) . integerValue ( BigNumber . ROUND_FLOOR ) . toNumber ( ) ; } function weightedFilter < T > ( input , startIn , endIn , getValueIn ) { const start = new BigNumber ( startIn ) ; const end = new BigNumber ( endIn ) ; const getValue = ( value ) => new BigNumber ( getValueIn ( value ) . toString ( 10 ) ) ; const amount = input . reduce ( ( acc , value ) => acc . plus ( getValue ( value ) ) , new BigNumber ( 0 ) ) ; let sum = new BigNumber ( 0 ) ; let current = new BigNumber ( 0 ) ; const mutableResult = [ ] ; for ( const value of input ) { if ( current . gte ( end ) ) { break ; } let weight = getValue ( value ) ; sum = sum . plus ( weight ) ; const old = current ; current = sum . div ( amount ) ; if ( current . lte ( start ) ) { continue ; } if ( old . lt ( start ) ) { weight = current . gt ( end ) ? end . minus ( start ) . times ( amount ) : current . minus ( start ) . times ( amount ) ; } else if ( current . gt ( end ) ) { weight = end . minus ( old ) . times ( amount ) ; } mutableResult . push ( [ value , weight . gte ( 0 ) ? weight . integerValue ( BigNumber . ROUND_FLOOR ) : weight . integerValue ( BigNumber . ROUND_CEIL ) , ] ) ; } return mutableResult ; } function equals < T > ( clazz , thiz , equalsFunc ) { return ( other ) : boolean => other != undefined && ( thiz === other || ( other instanceof clazz && equalsFunc ( other ) ) ) ; } const wildCardFromJSON = < T > ( json , selector ) => { if ( typeof json === 'string' ) { if ( json !== '*' ) { throw new InvalidFormatError ( ) ; } return '*' ; } if ( Array . isArray ( json ) ) { return json . map ( selector ) ; } throw new InvalidFormatError ( ) ; } ; const getInteroperable = < T > ( item , fromStackItem ) : T => { const buffer = item . value ; const reader = new BinaryReader ( buffer ) ; const deserializedStackItem = deserializeStackItem ( reader , executionLimits . maxStackSize , executionLimits . maxItemSize ) ; return fromStackItem ( deserializedStackItem ) ; } ; const getSerializableArray = < T > ( value , readValue , max = 0x1000000 ) : readonly T [ ] => { const reader = new BinaryReader ( value ) ; return reader . readArray ( ( ) => readValue ( reader ) , max ) ; } ; const getSerializableArrayFromStorageItem = < T > ( item , readValue , max = 0x1000000 ) : readonly T [ ] => { const value = item . value ; return getSerializableArray ( value , readValue , max ) ; } ; export const utils = { ... clientUtils , toASCII , toUTF8 , randomUInt64 , toKeyString , equals , lazyAsync , lazyOrValue , weightedAverage , weightedFilter , wildCardFromJSON , getInteroperable , getSerializableArray , getSerializableArrayFromStorageItem } ;