import 'dart:typed_data'; import 'package:coinlib_flutter/coinlib_flutter.dart' as coinlib; const OP_EXCHANGEADDR = 0xe0; class EXP2PKHAddress implements coinlib.Address { /// The 160bit public key or redeemScript hash for the base58 address final Uint8List _hash; /// The network and address type version of the address final Uint8List version; String? _encodedCache; EXP2PKHAddress._(Uint8List hash, this.version) : _hash = hash { if (version.length != 3) { throw ArgumentError( "version bytes length must be 3", ); } } factory EXP2PKHAddress.fromString(String encoded, Uint8List versionBytes) { if (versionBytes.length != 3) { throw ArgumentError( "version bytes length must be 3", ); } final data = coinlib.base58Decode(encoded); if (data.length != 23) throw coinlib.InvalidAddress(); final version = data.sublist(0, 3); for (int i = 0; i < 3; i++) { if (version[i] != versionBytes[i]) { throw Exception("EX address version bytes do not match"); } } final payload = data.sublist(3); final addr = EXP2PKHAddress._(payload, version); addr._encodedCache = encoded; return addr; } @override String toString() => _encodedCache.toString(); @override coinlib.Program get program => EXP2PKH.fromHash(_hash); } class EXP2PKH implements coinlib.Program { static const template = "OP_EXCHANGEADDR OP_DUP OP_HASH160 <20-bytes> OP_EQUALVERIFY OP_CHECKSIG"; @override final coinlib.Script script; EXP2PKH.fromScript(this.script); factory EXP2PKH.fromHash(Uint8List pkHash) { final List ops = [ coinlib.ScriptOpCode(OP_EXCHANGEADDR), ]; final parts = template.split(" ").sublist(1); for (final name in parts) { if (name.startsWith("OP_")) { ops.add( coinlib.ScriptOpCode( coinlib.scriptOpNameToCode[name.substring(3)]!, ), ); } else if (name == "<20-bytes>") { ops.add(coinlib.ScriptPushData(pkHash)); } else { throw Exception("Something went wrong in this hacked code"); } } return EXP2PKH.fromScript(coinlib.Script(ops)); } }