decode static method

({String hrp, Uint8List witnessProgram, int witnessVersion}) decode(
  1. String address
)

Decodes a Bech32/Bech32m address.

Returns (hrp, witnessVersion, witnessProgram).

Implementation

static ({String hrp, int witnessVersion, Uint8List witnessProgram}) decode(
    String address) {
  final lower = address.toLowerCase();
  final upper = address.toUpperCase();

  if (address != lower && address != upper) {
    throw FormatException('Mixed case in Bech32 address');
  }

  final pos = lower.lastIndexOf('1');
  if (pos < 1 || pos + 7 > lower.length || lower.length > 90) {
    throw FormatException('Invalid Bech32 format');
  }

  final hrp = lower.substring(0, pos);
  final dataStr = lower.substring(pos + 1);

  final data = <int>[];
  for (final c in dataStr.split('')) {
    final index = _charset.indexOf(c);
    if (index < 0) {
      throw FormatException('Invalid Bech32 character: $c');
    }
    data.add(index);
  }

  // Try Bech32m first, then Bech32
  var useBech32m = true;
  if (!_verifyChecksum(hrp, data, true)) {
    if (!_verifyChecksum(hrp, data, false)) {
      throw FormatException('Invalid Bech32 checksum');
    }
    useBech32m = false;
  }

  final values = data.sublist(0, data.length - 6);
  if (values.isEmpty) {
    throw FormatException('Empty Bech32 data');
  }

  final witnessVersion = values[0];
  if (witnessVersion > 16) {
    throw FormatException('Invalid witness version: $witnessVersion');
  }

  // Bech32m required for v1+
  if (witnessVersion == 0 && useBech32m) {
    throw FormatException('Bech32m used for witness v0');
  }
  if (witnessVersion > 0 && !useBech32m) {
    throw FormatException('Bech32 used for witness v$witnessVersion');
  }

  final program = _convertBits(values.sublist(1), 5, 8, false);
  if (program.length < 2 || program.length > 40) {
    throw FormatException('Invalid witness program length');
  }
  if (witnessVersion == 0 && program.length != 20 && program.length != 32) {
    throw FormatException('Invalid v0 witness program length');
  }
  if (witnessVersion == 1 && program.length != 32) {
    throw FormatException('Invalid v1 witness program length');
  }

  return (
    hrp: hrp,
    witnessVersion: witnessVersion,
    witnessProgram: Uint8List.fromList(program),
  );
}