decodeBchRawTx function

DecodedBchTx decodeBchRawTx(
  1. String rawTxHex
)

Hardened reader for the legacy (non-witness) transaction serialization.

Implementation

DecodedBchTx decodeBchRawTx(String rawTxHex) {
  Uint8List bytes;
  try {
    bytes = hexToBytes(rawTxHex);
  } on Object {
    throw EraSdkError('malformed-reply', 'signed transaction is not hex');
  }
  var offset = 0;
  void need(int n) {
    if (offset + n > bytes.length) {
      throw EraSdkError('malformed-reply', 'signed transaction is truncated');
    }
  }

  int readU32() {
    need(4);
    final v = bytes[offset] |
        (bytes[offset + 1] << 8) |
        (bytes[offset + 2] << 16) |
        (bytes[offset + 3] << 24);
    offset += 4;
    return v;
  }

  BigInt readU64() {
    need(8);
    var v = BigInt.zero;
    for (var i = 7; i >= 0; i--) {
      v = (v << 8) | BigInt.from(bytes[offset + i]);
    }
    offset += 8;
    return v;
  }

  int readVarint() {
    need(1);
    final first = bytes[offset++];
    if (first < 0xfd) return first;
    if (first == 0xfd) {
      need(2);
      final v = bytes[offset] | (bytes[offset + 1] << 8);
      offset += 2;
      return v;
    }
    // 4- and 8-byte counts cannot occur in a transaction the device can build.
    throw EraSdkError(
      'malformed-reply',
      'unreasonable varint in signed transaction',
    );
  }

  Uint8List readSlice(int n) {
    need(n);
    final s = Uint8List.sublistView(bytes, offset, offset + n);
    offset += n;
    return s;
  }

  final version = readU32();
  final inputCount = readVarint();
  if (inputCount == 0 || inputCount > 1000) {
    throw EraSdkError(
      'malformed-reply',
      'unreasonable input count in signed transaction',
    );
  }
  final inputs = <DecodedBchInput>[];
  for (var i = 0; i < inputCount; i++) {
    final txidLE = readSlice(32);
    final index = readU32();
    final scriptSig = readSlice(readVarint());
    final sequence = readU32();
    inputs.add(DecodedBchInput(
      txidLE: txidLE,
      index: index,
      scriptSig: scriptSig,
      sequence: sequence,
    ));
  }
  final outputCount = readVarint();
  if (outputCount == 0 || outputCount > 1000) {
    throw EraSdkError(
      'malformed-reply',
      'unreasonable output count in signed transaction',
    );
  }
  final outputs = <DecodedBchOutput>[];
  for (var i = 0; i < outputCount; i++) {
    final value = readU64();
    final script = readSlice(readVarint());
    outputs.add(DecodedBchOutput(value: value, script: script));
  }
  final locktime = readU32();
  if (offset != bytes.length) {
    throw EraSdkError(
      'malformed-reply',
      'trailing bytes after signed transaction',
    );
  }
  return DecodedBchTx(
    version: version,
    inputs: inputs,
    outputs: outputs,
    locktime: locktime,
  );
}