UNPKG

wallet-storage

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

284 lines (257 loc) 7.15 kB
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' import { CertOpsWallet } from '../sdk' export async function getIdentityKey( wallet: CertOpsWallet ): 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 if (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 { if (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 { if (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 { if (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 { if (!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 { if (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 { if (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) if (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 { if (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 { if (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) if ( 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[]) { if (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[]) { if (!arr1 && !arr2) return true if (!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() }