parsePsbt function

ParsedPsbt parsePsbt(
  1. Uint8List bytes
)

Parse bytes as a PSBT v0, refusing anything structurally off.

Implementation

ParsedPsbt parsePsbt(Uint8List bytes) {
  final reader = _Reader(bytes);
  for (final expected in _magic) {
    if (reader.u8() != expected) throw _err('bad magic');
  }
  final globalMap = _readMap(reader);

  Uint8List? unsignedTx;
  var version = 0;
  for (final entry in globalMap) {
    if (entry.keyType == 0x00 && entry.keyData.isEmpty) {
      unsignedTx = entry.value;
    }
    if (entry.keyType == 0xfb && entry.keyData.isEmpty) {
      if (entry.value.length != 4) throw _err('bad version field');
      version = entry.value[0] |
          (entry.value[1] << 8) |
          (entry.value[2] << 16) |
          (entry.value[3] << 24);
    }
  }
  if (unsignedTx == null) {
    // The device's signer relies on the global UNSIGNED_TX that only PSBT v0
    // carries; its absence means v2 (or not a PSBT at all).
    throw _err('no global unsigned transaction — not a PSBT v0');
  }
  if (version != 0) throw _err('unsupported PSBT version $version');

  final counts = _countTxInputsOutputs(unsignedTx);
  final inputs = <List<PsbtKeyValue>>[];
  for (var i = 0; i < counts.inputs; i++) {
    inputs.add(_readMap(reader));
  }
  final outputs = <List<PsbtKeyValue>>[];
  for (var i = 0; i < counts.outputs; i++) {
    outputs.add(_readMap(reader));
  }
  if (reader.remaining != 0) {
    throw _err('trailing bytes after the output maps');
  }

  return ParsedPsbt(
    unsignedTx: unsignedTx,
    version: version,
    inputs: inputs,
    outputs: outputs,
  );
}