decode static method
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),
);
}