All files / src/utility utilityHelpers.ts

74.07% Statements 80/108
35.55% Branches 16/45
77.77% Functions 21/27
82.22% Lines 74/90

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247  57x 57x     57x 4x     57x 1x     57x 7x 7x 7x 7x               57x                           57x 15x   15x 15x   15x             57x 6x             57x                 57x 706x 706x               57x                     57x                     57x 2x 2x               57x 21361x 21361x               57x 21361x 21361x 21361x                   57x 11529x 11529x                   57x 389x 389x             57x 3x           57x             57x 571x           57x 171x     57x                       57x 19x 19x 53x   15x     57x 5x 5x 5x     57x 11389x 11131x 5998x   258x 118x 12x               57x 2x 2x                 57x 18x 18x 18x                 57x 18x  
import { HexString, PubKeyHex, WalletInterface, WalletNetwork } from '@bsv/sdk'
import { Beef, Hash, PrivateKey, PublicKey, Random, Script, Transaction, Utils } from "@bsv/sdk";
import { sdk } from "../index.client";
import { Chain } from "../sdk/types";
 
export async function getIdentityKey(wallet: WalletInterface): Promise<PubKeyHex> {
  return (await wallet.getPublicKey({ identityKey: true })).publicKey
}
 
export function toWalletNetwork(chain: Chain): WalletNetwork {
    return chain === 'main' ? 'mainnet' : 'testnet';
}
 
export function makeAtomicBeef(tx: Transaction, beef: number[] | Beef) : number[] {
  if (Array.isArray(beef))
    beef = Beef.fromBinary(beef)
  beef.mergeTransaction(tx)
  return beef.toBinaryAtomic(tx.id('hex'))
}
 
/**
 * Coerce a bsv transaction encoded as a hex string, serialized array, or Transaction to Transaction
 * If tx is already a Transaction, just return it.
 * @publicbody
 */
export function asBsvSdkTx(tx: HexString | number[] | Transaction): Transaction {
  if (Array.isArray(tx)) {
    tx = Transaction.fromBinary(tx)
  } else Iif (typeof tx === 'string') {
    tx = Transaction.fromHex(tx)
  }
  return tx
}
 
/**
 * Coerce a bsv script encoded as a hex string, serialized array, or Script to Script
 * If script is already a Script, just return it.
 * @publicbody
 */
export function asBsvSdkScript(script: HexString | number[] | Script): Script {
  Iif (Array.isArray(script)) {
    script = Script.fromBinary(script)
  } else if (typeof script === 'string') {
    script = Script.fromHex(script)
  }
  return script
}
 
/**
 * @param privKey bitcoin private key in 32 byte hex string form
 * @returns @bsv/sdk PrivateKey
 */
export function asBsvSdkPrivateKey(privKey: string) : PrivateKey {
  return PrivateKey.fromString(privKey, 'hex')
}
 
/**
 * @param pubKey bitcoin public key in standard compressed key hex string form
 * @returns @bsv/sdk PublicKey
 */
export function asBsvSdkPublickKey(pubKey: string) : PublicKey {
  return PublicKey.fromString(pubKey)
}
 
/**
 * Helper function.
 *
 * Verifies that a possibly optional value has a value.
 */
export function verifyTruthy<T> (v: T | null | undefined, description?: string): T {
  Iif (v == null) throw new sdk.WERR_INTERNAL(description ?? 'A truthy value is required.')
  return v
}
 
/**
 * Helper function.
 *
 * Verifies that a hex string is trimmed and lower case.
 */
export function verifyHexString (v: string): string {
  Iif (typeof v !== 'string') throw new sdk.WERR_INTERNAL('A string is required.');
  v = v.trim().toLowerCase()
  return v
}
 
/**
 * Helper function.
 *
 * Verifies that an optional or null hex string is undefined or a trimmed lowercase string.
 */
export function verifyOptionalHexString (v?: string | null): string | undefined {
  Iif (!v) return undefined
  return verifyHexString(v)
}
 
 
/**
 * Helper function.
 *
 * Verifies that an optional or null number has a numeric value.
 */
export function verifyNumber (v: number | null | undefined): number {
  Iif (typeof v !== 'number') throw new sdk.WERR_INTERNAL('A number is required.')
  return v
}
 
/**
 * Helper function.
 *
 * Verifies that an optional or null number has a numeric value.
 */
export function verifyInteger (v: number | null | undefined): number {
  Iif (typeof v !== 'number' || !Number.isInteger(v)) throw new sdk.WERR_INTERNAL('An integer is required.');
  return v
}
 
/**
 * Helper function.
 * 
 * Verifies that a database record identifier is an integer greater than zero.
 */
export function verifyId(id : number | undefined | null) : number {
  id = verifyInteger(id)
  Iif (id < 1) throw new sdk.WERR_INTERNAL(`id must be valid integer greater than zero.`)
  return id
}
 
/**
 * Helper function.
 *
 * @throws WERR_BAD_REQUEST if results has length greater than one.
 *
 * @returns results[0] or undefined if length is zero.
 */
export function verifyOneOrNone<T> (results: T[]): (T | undefined) {
  Iif (results.length > 1) throw new sdk.WERR_BAD_REQUEST('Result must be unique.')
  return results[0]
}
 
/**
 * Helper function.
 *
 * @throws WERR_BAD_REQUEST if results has length other than one.
 *
 * @returns results[0].
 */
export function verifyOne<T> (results: T[], errorDescrition?: string): T {
  Iif (results.length !== 1) throw new sdk.WERR_BAD_REQUEST(errorDescrition ?? 'Result must exist and be unique.')
  return results[0]
}
 
/**
 * Returns an await'able Promise that resolves in the given number of msecs.
 * @publicbody
 */
export function wait(msecs: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, msecs))
}
 
/**
 * @returns count cryptographically secure random bytes as array of bytes
 */
export function randomBytes(count: number): number[] {
  return Random(count)
}
 
/**
 * @returns count cryptographically secure random bytes as hex encoded string
 */
export function randomBytesHex(count: number): string {
  return Utils.toHex(Random(count))
}
 
/**
 * @returns count cryptographically secure random bytes as base64 encoded string
 */
export function randomBytesBase64(count: number): string {
  return Utils.toBase64(Random(count))
}
 
export function validateSecondsSinceEpoch (time: number): Date {
  const date = new Date(time * 1000)
  Iif (date.getTime() / 1000 !== time || time < 1600000000 || time > 100000000000) { throw new sdk.WERR_INVALID_PARAMETER('time', `valid "since epoch" unix time`) }
  return date
}
 
/**
 * Compares lengths and direct equality of values.
 * @param arr1 
 * @param arr2 
 * @returns 
 */
export function arraysEqual(arr1: Number[], arr2: Number[]) {
  Iif (arr1.length !== arr2.length) return false;
  for (let i = 0; i < arr1.length; i++) {
      if (arr1[i] !== arr2[i]) return false;
  }
  return true;
}
 
export function optionalArraysEqual(arr1?: Number[], arr2?: Number[]) {
  Iif (!arr1 && !arr2) return true
  Iif (!arr1 || !arr2) return false
  return arraysEqual(arr1, arr2)
}
 
export function maxDate(d1?: Date, d2?: Date) : Date | undefined {
    if (d1 && d2) {
        if (d1 > d2) return d1
        return d2
    }
    if (d1) return d1
    if (d2) return d2
    return undefined
}
 
/**
 * Calculate the SHA256 hash of an array of bytes
 * @returns sha256 hash of buffer contents.
 * @publicbody
 */
export function sha256Hash(data: number[]): number[] {
    const first = new Hash.SHA256().update(data).digest()
    return first
}
 
/**
 * Calculate the SHA256 hash of the SHA256 hash of an array of bytes.
 * @param data an array of bytes
 * @returns double sha256 hash of data, byte 0 of hash first.
 * @publicbody
 */
export function doubleSha256HashLE (data: number[]): number[] {
    const first = new Hash.SHA256().update(data).digest()
    const second = new Hash.SHA256().update(first).digest()
    return second
}
 
/**
 * Calculate the SHA256 hash of the SHA256 hash of an array of bytes.
 * @param data is an array of bytes.
 * @returns reversed (big-endian) double sha256 hash of data, byte 31 of hash first.
 * @publicbody
 */
export function doubleSha256BE (data: number[]): number[] {
    return doubleSha256HashLE(data).reverse()
}