parsePsbt function
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,
);
}