or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-bitcoin.mdcryptography.mdencryption.mdhd-wallets.mdindex.mdtransaction-building.mdutilities.md
tile.json

utilities.mddocs/

Utilities

Base classes, encoding utilities, workers, and supporting infrastructure for the BSV library.

Imports

// ES6 imports
import { 
  Struct, Bn, Br, Bw, Base58, Base58Check, 
  VarInt, OpCode, Constants, Random, Workers 
} from 'bsv'

// CommonJS imports
const { 
  Struct, Bn, Br, Bw, Base58, Base58Check, 
  VarInt, OpCode, Constants, Random, Workers 
} = require('bsv')

Struct (Base Class)

Base class providing common serialization methods for all BSV objects.

Class Definition

class Struct {
  constructor(obj?: object)  // Initialize from object

  // Object initialization
  fromObject(obj: object): this  // Set properties from object

  // Binary serialization
  fromBuffer(buf: Buffer): this    // Parse from binary buffer
  toBuffer(): Buffer              // Serialize to binary buffer
  fromFastBuffer(buf: Buffer): this  // Fast binary parsing
  toFastBuffer(): Buffer          // Fast binary serialization

  // Hexadecimal serialization  
  fromHex(hex: string): this      // Parse from hex string
  toHex(): string                 // Serialize to hex string

  // String serialization (custom format)
  fromString(str: string): this   // Parse from string
  toString(): string              // Serialize to string

  // JSON serialization
  fromJSON(json: object): this    // Parse from JSON object
  toJSON(): object               // Serialize to JSON object

  // Binary reader/writer serialization
  fromBr(br: Br): this           // Parse using buffer reader
  toBw(bw?: Bw): Bw              // Serialize using buffer writer

  // Utility methods
  clone(): this                  // Deep clone object

  // Generator methods for streaming
  genFromBuffers(): Generator    // Generator for streaming deserialization
  expect(len: number, startbuf?: Buffer): Buffer  // Helper for generators
}

Usage Examples

// Most BSV classes extend Struct and inherit these methods
const privKey = PrivKey.fromRandom()

// Hex serialization
const hex = privKey.toHex()
const privKey2 = PrivKey.fromHex(hex)

// JSON serialization  
const json = privKey.toJSON()
const privKey3 = PrivKey.fromJSON(json)

// Buffer serialization
const buffer = privKey.toBuffer()
const privKey4 = PrivKey.fromBuffer(buffer)

// Cloning
const clone = privKey.clone()

// Object initialization
const privKey5 = new PrivKey().fromObject({
  bn: Bn.fromNumber(12345),
  compressed: true
})

Bn (Big Number)

Arbitrary precision arithmetic extending the bn.js library for Bitcoin operations.

Class Definition

class Bn extends BN {
  constructor(
    n?: number | string | Buffer,  // Number, string, or buffer
    base?: number,                 // Number base (2, 8, 10, 16)
    endian?: string               // Byte order ('big', 'little')
  )

  // Buffer conversion
  static fromBuffer(
    buf: Buffer, 
    opts?: {
      endian?: string,    // 'big' or 'little' endian
      size?: number       // Expected size
    }
  ): Bn
  
  toBuffer(opts?: {
    endian?: string,      // 'big' or 'little' endian  
    size?: number         // Fixed size (zero-padded)
  }): Buffer

  // Signed magnitude format (Bitcoin-specific)
  static fromSm(
    buf: Buffer,
    opts?: { endian?: string }
  ): Bn
  
  toSm(opts?: { endian?: string }): Buffer

  // String conversion
  static fromString(str: string, base?: number): Bn
  toString(base?: number): string

  // Number conversion
  static fromNumber(n: number): Bn
  toNumber(): number

  // Hex convenience methods
  static fromHex(hex: string): Bn
  toHex(): string

  // Random number generation
  static fromRandom(): Bn
}

Usage Examples

// Create big numbers from various sources
const bn1 = Bn.fromNumber(12345)
const bn2 = Bn.fromString('123456789012345678901234567890')
const bn3 = Bn.fromHex('deadbeef')
const bn4 = Bn.fromBuffer(Buffer.from([0x01, 0x02, 0x03, 0x04]))

// Arithmetic operations (inherited from bn.js)
const sum = bn1.add(bn2)
const diff = bn2.sub(bn1)
const product = bn1.mul(bn2)
const quotient = bn2.div(bn1)
const remainder = bn2.mod(bn1)

// Bitcoin-specific signed magnitude format
const signed = Bn.fromNumber(-12345)
const smBuffer = signed.toSm()
const restored = Bn.fromSm(smBuffer)

// Buffer operations with endianness
const buffer = bn3.toBuffer({ endian: 'little', size: 8 })
const restored2 = Bn.fromBuffer(buffer, { endian: 'little' })

// Comparisons
const isEqual = bn1.eq(bn2)
const isGreater = bn1.gt(bn2)
const isLess = bn1.lt(bn2)

// Generate random big number
const randomBn = Bn.fromRandom()

// Fixed-size serialization (for keys, hashes, etc.)
const bn256bit = Bn.fromNumber(12345)
const key = bn256bit.toBuffer({ size: 32 }) // 32-byte buffer
console.log('Key length:', key.length) // 32

Buffer Reader (Br)

Sequential buffer reading with built-in Bitcoin data type support.

Class Definition

class Br {
  constructor(buf?: Buffer)

  // Core properties
  buf: Buffer         // Source buffer
  pos: number         // Current position

  // Basic reading
  read(len: number): Buffer              // Read bytes
  readReverse(len: number): Buffer       // Read bytes in reverse order

  // Integer reading (little endian)
  readUInt8(): number                    // Read 1-byte unsigned integer
  readUInt16LE(): number                 // Read 2-byte unsigned integer
  readUInt32LE(): number                 // Read 4-byte unsigned integer
  readUInt64LEBn(): Bn                   // Read 8-byte unsigned integer as Bn

  // Variable-length integers (Bitcoin VarInt format)
  readVarIntNum(): number                // Read VarInt as number
  readVarIntBuf(): Buffer               // Read VarInt as buffer
  readVarIntBn(): Bn                    // Read VarInt as big number

  // Utility
  eof(): boolean                        // Check if at end of buffer
}

Usage Examples

// Create buffer with mixed data
const bw = new Bw()
bw.writeUInt8(42)
bw.writeUInt32LE(123456)
bw.writeVarIntNum(999999)
bw.write(Buffer.from('hello', 'utf8'))
const buffer = bw.toBuffer()

// Read data sequentially
const br = new Br(buffer)

const byte = br.readUInt8()           // 42
const int32 = br.readUInt32LE()       // 123456
const varInt = br.readVarIntNum()     // 999999
const remaining = br.read(5)          // Buffer('hello')

console.log('Read:', { byte, int32, varInt, remaining: remaining.toString() })
console.log('At EOF:', br.eof())

// Read Bitcoin transaction format
const txBuffer = tx.toBuffer()
const br2 = new Br(txBuffer)

const version = br2.readUInt32LE()
const inputCount = br2.readVarIntNum()
// ... continue reading transaction structure

Buffer Writer (Bw)

Sequential buffer writing with built-in Bitcoin data type support.

Class Definition

class Bw {
  constructor()

  // Core properties
  bufs: Buffer[]      // Array of written buffers

  // Basic writing
  write(buf: Buffer): Bw                 // Write buffer
  writeReverse(buf: Buffer): Bw          // Write buffer in reverse order

  // Integer writing (little endian)
  writeUInt8(n: number): Bw              // Write 1-byte unsigned integer
  writeUInt16LE(n: number): Bw           // Write 2-byte unsigned integer
  writeUInt32LE(n: number): Bw           // Write 4-byte unsigned integer
  writeUInt64LEBn(bn: Bn): Bw            // Write 8-byte unsigned integer from Bn

  // Variable-length integers (Bitcoin VarInt format)
  writeVarIntNum(n: number): Bw          // Write number as VarInt
  writeVarIntBuf(buf: Buffer): Bw        // Write buffer length + buffer
  writeVarIntBn(bn: Bn): Bw              // Write big number as VarInt

  // Result
  toBuffer(): Buffer                     // Get final concatenated buffer
}

Usage Examples

// Build complex binary structure
const bw = new Bw()

// Write transaction version
bw.writeUInt32LE(1)

// Write input count
bw.writeVarIntNum(2)

// Write transaction inputs
for (const txIn of txIns) {
  bw.write(txIn.txHashBuf)        // Previous tx hash (32 bytes)
  bw.writeUInt32LE(txIn.txOutNum) // Output index (4 bytes)
  bw.writeVarIntBuf(txIn.script.toBuffer()) // Script with length prefix
  bw.writeUInt32LE(txIn.nSequence) // Sequence (4 bytes)
}

// Write output count and outputs
bw.writeVarIntNum(txOuts.length)
for (const txOut of txOuts) {
  bw.writeUInt64LEBn(txOut.valueBn)     // Value as 8-byte integer
  bw.writeVarIntBuf(txOut.script.toBuffer()) // Script with length prefix
}

// Write lock time
bw.writeUInt32LE(0)

// Get final transaction buffer
const txBuffer = bw.toBuffer()

Base58 Encoding

Bitcoin's Base58 encoding for human-readable data representation.

Class Definition

class Base58 {
  // Core encoding/decoding
  static encode(buf: Buffer): string     // Encode buffer to Base58 string
  static decode(str: string): Buffer     // Decode Base58 string to buffer
}

Usage Examples

// Encode binary data to Base58
const data = Buffer.from('Hello, Base58!', 'utf8')
const encoded = Base58.encode(data)
console.log('Base58:', encoded) // "2NEpo7TZRhna7vSvL"

// Decode Base58 to binary
const decoded = Base58.decode(encoded)
console.log('Decoded:', decoded.toString('utf8')) // "Hello, Base58!"

// Base58 alphabet excludes confusing characters: 0, O, I, l
const alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

Base58Check

Base58 encoding with checksum for error detection (used in Bitcoin addresses and keys).

Class Definition

class Base58Check {
  // Encoding/decoding with checksum
  static encode(buf: Buffer): string     // Encode with 4-byte checksum
  static decode(str: string): Buffer     // Decode and verify checksum
}

Usage Examples

// Create Bitcoin address manually
const version = Buffer.from([0x00]) // Mainnet P2PKH version
const hash160 = Hash.sha256Ripemd160(pubKey.toBuffer())
const payload = Buffer.concat([version, hash160])
const address = Base58Check.encode(payload)

// Decode and verify Bitcoin address
try {
  const decoded = Base58Check.decode(address)
  const version = decoded[0]
  const hash = decoded.slice(1)
  console.log('Valid address, version:', version, 'hash:', hash.toString('hex'))
} catch (error) {
  console.error('Invalid address checksum')
}

// Private key WIF encoding
const privKeyBytes = privKey.bn.toBuffer({ size: 32 })
const wifVersion = Buffer.from([0x80]) // Mainnet private key version
const compressed = Buffer.from([0x01]) // Compression flag
const wifPayload = Buffer.concat([wifVersion, privKeyBytes, compressed])
const wif = Base58Check.encode(wifPayload)

VarInt (Variable-Length Integers)

Bitcoin's variable-length integer encoding for space-efficient integer storage.

Class Definition

class VarInt {
  constructor(buf?: Buffer)

  // Core properties
  buf: Buffer         // VarInt buffer representation

  // Creation methods
  static fromNumber(num: number): VarInt   // Create from number
  static fromBuffer(buf: Buffer): VarInt   // Parse from buffer

  // Conversion methods
  toNumber(): number                       // Convert to number
  toBuffer(): Buffer                       // Get buffer representation
}

Usage Examples

// VarInt encoding examples
const small = VarInt.fromNumber(252)     // 1 byte: 0xfc
const medium = VarInt.fromNumber(253)    // 3 bytes: 0xfd 0xfd 0x00
const large = VarInt.fromNumber(65536)   // 3 bytes: 0xfd 0x00 0x01
const huge = VarInt.fromNumber(16777216) // 5 bytes: 0xfe 0x00 0x00 0x00 0x01

console.log('Small VarInt:', small.toBuffer().toString('hex'))
console.log('Medium VarInt:', medium.toBuffer().toString('hex'))

// Parse VarInt from buffer
const buffer = Buffer.from([0xfd, 0x34, 0x12]) // 0x1234 = 4660
const varInt = VarInt.fromBuffer(buffer)
console.log('Parsed value:', varInt.toNumber()) // 4660

// VarInt size calculation
function getVarIntSize(num) {
  if (num < 0xfd) return 1          // 1 byte
  if (num <= 0xffff) return 3       // 3 bytes (0xfd + 2 bytes)
  if (num <= 0xffffffff) return 5   // 5 bytes (0xfe + 4 bytes)
  return 9                          // 9 bytes (0xff + 8 bytes)
}

OpCode

Bitcoin Script operation codes with complete opcode definitions.

Class Definition

class OpCode {
  constructor(num?: number)

  // Core properties
  num: number         // Opcode number

  // Creation methods
  static fromNumber(num: number): OpCode     // Create from number
  static fromString(str: string): OpCode     // Create from string name

  // Conversion methods
  toNumber(): number                         // Get opcode number
  toString(): string                         // Get opcode name

  // All Bitcoin opcodes as static constants
  static OP_0: number              // 0x00 - Push empty array
  static OP_1: number              // 0x51 - Push number 1
  static OP_2: number              // 0x52 - Push number 2
  // ... continuing through OP_16

  // Data push opcodes
  static OP_PUSHDATA1: number      // 0x4c - Push next byte as data length
  static OP_PUSHDATA2: number      // 0x4d - Push next 2 bytes as data length
  static OP_PUSHDATA4: number      // 0x4e - Push next 4 bytes as data length

  // Flow control
  static OP_IF: number             // 0x63 - Execute if top of stack is true
  static OP_ELSE: number           // 0x67 - Execute if OP_IF was false
  static OP_ENDIF: number          // 0x68 - End if/else block
  static OP_RETURN: number         // 0x6a - Mark output as unspendable

  // Stack operations
  static OP_DUP: number            // 0x76 - Duplicate top stack item
  static OP_DROP: number           // 0x75 - Remove top stack item
  static OP_SWAP: number           // 0x7c - Swap top two stack items

  // Cryptographic operations
  static OP_HASH160: number        // 0xa9 - SHA256 + RIPEMD160
  static OP_CHECKSIG: number       // 0xac - Check signature
  static OP_CHECKMULTISIG: number  // 0xae - Check multisig

  // Comparison operations  
  static OP_EQUAL: number          // 0x87 - Return 1 if equal
  static OP_EQUALVERIFY: number    // 0x88 - Equal + verify (fail if false)

  // ... many more opcodes defined
}

Usage Examples

// Create opcodes from numbers and strings
const opDup = OpCode.fromNumber(OpCode.OP_DUP)
const opHash160 = OpCode.fromString('OP_HASH160')

// Build P2PKH script using opcodes
const script = new Script()
script.writeOpCode(OpCode.OP_DUP)
script.writeOpCode(OpCode.OP_HASH160)
script.writeBuffer(pubKeyHashBuf) // 20 bytes
script.writeOpCode(OpCode.OP_EQUALVERIFY)
script.writeOpCode(OpCode.OP_CHECKSIG)

// Opcode information
console.log('OP_DUP number:', OpCode.OP_DUP)           // 118
console.log('OP_DUP string:', opDup.toString())        // "OP_DUP"
console.log('OP_RETURN number:', OpCode.OP_RETURN)     // 106

// Common opcode patterns
const opcodes = {
  // Standard P2PKH
  p2pkh: [OpCode.OP_DUP, OpCode.OP_HASH160, OpCode.OP_EQUALVERIFY, OpCode.OP_CHECKSIG],
  
  // OP_RETURN data
  opReturn: [OpCode.OP_RETURN],
  
  // Safe OP_RETURN (OP_FALSE OP_RETURN)
  safeOpReturn: [OpCode.OP_0, OpCode.OP_RETURN],
  
  // 2-of-3 multisig
  multisig2of3: [OpCode.OP_2, OpCode.OP_3, OpCode.OP_CHECKMULTISIG]
}

Constants

Network-specific configuration constants for mainnet, testnet, and other networks.

Class Definition

class Constants {
  // Network configurations
  static Mainnet: {
    Address: {
      pubKeyHash: number,        // P2PKH version byte (0x00)
      scriptHash: number         // P2SH version byte (0x05)
    },
    Bip32: {
      pubKey: number,           // xpub version (0x0488b21e)
      privKey: number           // xprv version (0x0488ade4)
    },
    PrivKey: {
      version: number           // Private key WIF version (0x80)
    },
    TxBuilder: {
      dust: number,            // Dust threshold (546 satoshis)
      feePerKbNum: number      // Default fee rate (400 sat/KB)
    },
    Block: {
      maxNBits: number,        // Maximum difficulty target
      magicNum: number         // Network magic number
    }
  }

  static Testnet: {
    // Similar structure with testnet values
  }

  static Regtest: {
    // Similar structure with regtest values
  }

  static STN: {
    // Similar structure with STN values
  }

  static Default: object      // Currently selected network (usually Mainnet)

  // Utility method
  static getConstants(magicNum: number): object  // Get constants by magic number
}

Usage Examples

// Access mainnet constants
const mainnet = Constants.Mainnet
console.log('Mainnet P2PKH version:', mainnet.Address.pubKeyHash) // 0
console.log('Mainnet xprv version:', mainnet.Bip32.privKey.toString(16)) // 488ade4

// Access testnet constants  
const testnet = Constants.Testnet
console.log('Testnet P2PKH version:', testnet.Address.pubKeyHash) // 111

// Use with classes
const mainnetAddress = new Address(
  Constants.Mainnet.Address.pubKeyHash,
  hashBuf,
  Constants.Mainnet
)

const testnetPrivKey = new PrivKey(
  bn,
  true,
  Constants.Testnet
)

// Network-specific classes automatically use appropriate constants
const mainnetAddr = Address.Mainnet.fromRandom() // Uses mainnet constants
const testnetAddr = Address.Testnet.fromRandom() // Uses testnet constants

// Get constants by magic number
const constants = Constants.getConstants(0xe3e1f3e8) // Mainnet magic

Random

Cryptographically secure random number generation.

Class Definition

class Random {
  // Generate cryptographically secure random bytes
  static getRandomBuffer(size: number): Buffer
}

Usage Examples

// Generate random data for cryptographic use
const randomKey = Random.getRandomBuffer(32)     // 256-bit key
const randomIv = Random.getRandomBuffer(16)      // 128-bit IV
const randomNonce = Random.getRandomBuffer(32)   // 256-bit nonce
const randomSalt = Random.getRandomBuffer(16)    // 128-bit salt

// Use for key generation
const privKey = PrivKey.fromBn(Bn.fromBuffer(randomKey))
const keyPair = KeyPair.fromPrivKey(privKey)

// Use for encryption
const message = Buffer.from('Secret message', 'utf8')
const encrypted = Aescbc.encrypt(message, randomKey, randomIv)

// Generate random transaction nonce
const txNonce = Random.getRandomBuffer(4).readUInt32LE(0)

Workers

Background computation management for non-blocking cryptographic operations.

Class Definition

class Workers {
  // Instance methods
  asyncObjectMethod(
    obj: object,           // Object instance
    methodName: string,    // Method name to call
    args: any[],          // Method arguments
    id?: string           // Operation ID
  ): Promise<any>

  asyncClassMethod(
    classObj: Function,    // Class constructor
    methodName: string,    // Static method name
    args: any[],          // Method arguments  
    id?: string           // Operation ID
  ): Promise<any>

  // Static methods
  static asyncObjectMethod(...args): Promise<any>
  static asyncClassMethod(...args): Promise<any>
  static endGlobalWorkers(): void   // Cleanup global workers
}

Usage Examples

// Async object method execution
const privKey = PrivKey.fromRandom()
const workers = new Workers()

// Execute private key methods in background
const address = await workers.asyncObjectMethod(privKey, 'toAddress', [])
const wif = await workers.asyncObjectMethod(privKey, 'toWif', [])

// Async class method execution (static methods)
const hashBuf = await workers.asyncClassMethod(Hash, 'sha256', [dataBuf])
const sig = await workers.asyncClassMethod(Ecdsa, 'sign', [hashBuf, keyPair])

// Global workers (shared across application)
const globalHashResult = await Workers.asyncClassMethod(Hash, 'sha256Sha256', [largeBuf])
const globalSigResult = await Workers.asyncObjectMethod(tx, 'sign', [keyPair, nHashType, nIn, subScript, valueBn])

// Cleanup when application ends
Workers.endGlobalWorkers()

// Batch operations
const operations = [
  Workers.asyncClassMethod(Hash, 'sha256', [buf1]),
  Workers.asyncClassMethod(Hash, 'sha256', [buf2]),
  Workers.asyncClassMethod(Hash, 'sha256', [buf3])
]

const results = await Promise.all(operations)
console.log('Hashed', results.length, 'buffers in parallel')

Advanced Utility Patterns

Streaming Transaction Parsing

// Parse large transactions using generators
function* parseTransactionStream(buffer) {
  const br = new Br(buffer)
  
  // Parse version
  const version = br.readUInt32LE()
  yield { type: 'version', value: version }
  
  // Parse inputs
  const inputCount = br.readVarIntNum()
  yield { type: 'inputCount', value: inputCount }
  
  for (let i = 0; i < inputCount; i++) {
    const txHash = br.read(32)
    const outputIndex = br.readUInt32LE()
    const scriptLen = br.readVarIntNum()
    const script = br.read(scriptLen)
    const sequence = br.readUInt32LE()
    
    yield {
      type: 'input',
      index: i,
      txHash: txHash.toString('hex'),
      outputIndex,
      script: script.toString('hex'),
      sequence
    }
  }
  
  // Parse outputs
  const outputCount = br.readVarIntNum()
  yield { type: 'outputCount', value: outputCount }
  
  for (let i = 0; i < outputCount; i++) {
    const value = br.readUInt64LEBn()
    const scriptLen = br.readVarIntNum()
    const script = br.read(scriptLen)
    
    yield {
      type: 'output',
      index: i,
      value: value.toString(),
      script: script.toString('hex')
    }
  }
  
  // Parse lock time
  const lockTime = br.readUInt32LE()
  yield { type: 'lockTime', value: lockTime }
}

// Usage
const txBuffer = tx.toBuffer()
for (const part of parseTransactionStream(txBuffer)) {
  console.log(part.type, part)
}

Custom Serialization

// Create custom serializable class extending Struct
class CustomData extends Struct {
  constructor(name, value, timestamp) {
    super({ name, value, timestamp })
  }
  
  fromBr(br) {
    const nameLen = br.readVarIntNum()
    this.name = br.read(nameLen).toString('utf8')
    this.value = br.readUInt64LEBn()
    this.timestamp = br.readUInt32LE()
    return this
  }
  
  toBw(bw) {
    bw = bw || new Bw()
    const nameBuf = Buffer.from(this.name, 'utf8')
    bw.writeVarIntNum(nameBuf.length)
    bw.write(nameBuf)
    bw.writeUInt64LEBn(this.value)
    bw.writeUInt32LE(this.timestamp)
    return bw
  }
}

// Usage
const data = new CustomData('test', Bn.fromNumber(12345), Date.now())
const buffer = data.toBuffer()
const restored = CustomData.fromBuffer(buffer)

Batch Processing with Workers

// Process large datasets with workers
async function batchHashFiles(files) {
  const workers = new Workers()
  
  // Process files in batches to avoid memory issues
  const batchSize = 10
  const results = []
  
  for (let i = 0; i < files.length; i += batchSize) {
    const batch = files.slice(i, i + batchSize)
    
    const batchPromises = batch.map(async (file) => {
      const data = await readFile(file)
      return workers.asyncClassMethod(Hash, 'sha256', [data], file)
    })
    
    const batchResults = await Promise.all(batchPromises)
    results.push(...batchResults)
    
    console.log(`Processed batch ${Math.floor(i/batchSize) + 1}`)
  }
  
  workers.endGlobalWorkers()
  return results
}

Error Handling

Utility classes include comprehensive validation:

// Buffer bounds checking
try {
  const br = new Br(Buffer.alloc(10))
  br.read(20) // Trying to read more than available
} catch (error) {
  console.error('Buffer underflow:', error.message)
}

// VarInt validation
try {
  const invalidVarInt = Buffer.from([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
  VarInt.fromBuffer(invalidVarInt) // May be too large
} catch (error) {
  console.error('Invalid VarInt:', error.message)
}

// Base58Check validation
try {
  const corruptedAddress = '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN3' // Wrong checksum
  Base58Check.decode(corruptedAddress)
} catch (error) {
  console.error('Checksum validation failed:', error.message)
}

// OpCode validation
try {
  const invalidOpCode = OpCode.fromNumber(300) // Non-existent opcode
} catch (error) {
  console.error('Invalid opcode:', error.message)
}