export enum ScriptNumberError { outOfRange = 'Failed to parse Script Number: overflows Script Number range.' , requiresMinimal = 'Failed to parse Script Number: the number is not minimally-encoded.' } export const isScriptNumberError = ( value ) : value is ScriptNumberError => value === ScriptNumberError . outOfRange || value === ScriptNumberError . requiresMinimal ; const normalMaximumScriptNumberByteLength = 4 ; remarks param bytes param requireMinimalEncoding param maximumScriptNumberByteLength export const parseBytesAsScriptNumber = ( bytes , { maximumScriptNumberByteLength = normalMaximumScriptNumberByteLength , requireMinimalEncoding = true , } = { maximumScriptNumberByteLength : normalMaximumScriptNumberByteLength , requireMinimalEncoding : true , } ) : bigint | ScriptNumberError => { if ( bytes . length === 0 ) { return BigInt ( 0 ) ; } if ( bytes . length > maximumScriptNumberByteLength ) { return ScriptNumberError . outOfRange ; } const mostSignificantByte = bytes [ bytes . length - 1 ] ; const secondMostSignificantByte = bytes [ bytes . length - 1 - 1 ] ; const allButTheSignBit = 127 ; const justTheSignBit = 128 ; if ( requireMinimalEncoding && ( mostSignificantByte & allButTheSignBit ) === 0 && ( bytes . length <= 1 || ( secondMostSignificantByte & justTheSignBit ) === 0 ) ) { return ScriptNumberError . requiresMinimal ; } const bitsPerByte = 8 ; const signFlippingByte = 0x80 ; let result = BigInt ( 0 ) ; for ( let byte = 0 ; byte < bytes . length ; byte ++ ) { result |= BigInt ( bytes [ byte ] ) << BigInt ( byte * bitsPerByte ) ; } const isNegative = ( bytes [ bytes . length - 1 ] & signFlippingByte ) !== 0 ; return isNegative ? - ( result & ~ ( BigInt ( signFlippingByte ) << BigInt ( bitsPerByte * ( bytes . length - 1 ) ) ) ) : result ; } ; param integer export const bigIntToScriptNumber = ( integer ) : Uint8Array => { if ( integer === BigInt ( 0 ) ) { return new Uint8Array ( ) ; } const bytes = [ ] ; const isNegative = integer < 0 ; const byteStates = 0xff ; const bitsPerByte = 8 ; let remaining = isNegative ? - integer : integer ; while ( remaining > 0 ) { bytes . push ( Number ( remaining & BigInt ( byteStates ) ) ) ; remaining >>= BigInt ( bitsPerByte ) ; } const signFlippingByte = 0x80 ; if ( ( bytes [ bytes . length - 1 ] & signFlippingByte ) > 0 ) { bytes . push ( isNegative ? signFlippingByte : 0x00 ) ; } else if ( isNegative ) { bytes [ bytes . length - 1 ] |= signFlippingByte ; } return new Uint8Array ( bytes ) ; } ; param item export const stackItemIsTruthy = ( item ) => { const signFlippingByte = 0x80 ; for ( let i = 0 ; i < item . length ; i ++ ) { if ( item [ i ] !== 0 ) { if ( i === item . length - 1 && item [ i ] === signFlippingByte ) { return false ; } return true ; } } return false ; } ; param value export const booleanToScriptNumber = ( value ) => value ? bigIntToScriptNumber ( BigInt ( 1 ) ) : bigIntToScriptNumber ( BigInt ( 0 ) ) ;