added extra checks to BCH as well as test cases

This commit is contained in:
julian 2022-11-07 14:46:36 -06:00
parent 48a0e3a5ca
commit c962f597fd
2 changed files with 199 additions and 23 deletions

View file

@ -208,9 +208,9 @@ class BitcoinCashWallet extends CoinServiceAPI {
_getCurrentAddressForChain(0, DerivePathType.bip44); _getCurrentAddressForChain(0, DerivePathType.bip44);
Future<String>? _currentReceivingAddressP2PKH; Future<String>? _currentReceivingAddressP2PKH;
Future<String> get currentReceivingAddressP2SH => // Future<String> get currentReceivingAddressP2SH =>
_currentReceivingAddressP2SH ??= // _currentReceivingAddressP2SH ??=
_getCurrentAddressForChain(0, DerivePathType.bip49); // _getCurrentAddressForChain(0, DerivePathType.bip49);
Future<String>? _currentReceivingAddressP2SH; Future<String>? _currentReceivingAddressP2SH;
@override @override
@ -269,7 +269,11 @@ class BitcoinCashWallet extends CoinServiceAPI {
try { try {
if (bitbox.Address.detectFormat(address) == if (bitbox.Address.detectFormat(address) ==
bitbox.Address.formatCashAddr) { bitbox.Address.formatCashAddr) {
address = bitbox.Address.toLegacyAddress(address); if (validateCashAddr(address)) {
address = bitbox.Address.toLegacyAddress(address);
} else {
throw ArgumentError('$address is not currently supported');
}
} }
} catch (e, s) {} } catch (e, s) {}
try { try {
@ -294,11 +298,14 @@ class BitcoinCashWallet extends CoinServiceAPI {
} catch (err) { } catch (err) {
// Bech32 decode fail // Bech32 decode fail
} }
if (_network.bech32 != decodeBech32!.hrp) {
throw ArgumentError('Invalid prefix or Network mismatch'); if (decodeBech32 != null) {
} if (_network.bech32 != decodeBech32.hrp) {
if (decodeBech32.version != 0) { throw ArgumentError('Invalid prefix or Network mismatch');
throw ArgumentError('Invalid address version'); }
if (decodeBech32.version != 0) {
throw ArgumentError('Invalid address version');
}
} }
} }
throw ArgumentError('$address has no matching Script'); throw ArgumentError('$address has no matching Script');
@ -1203,6 +1210,15 @@ class BitcoinCashWallet extends CoinServiceAPI {
_transactionData = Future(() => cachedTxData!); _transactionData = Future(() => cachedTxData!);
} }
bool validateCashAddr(String cashAddr) {
String addr = cashAddr;
if (cashAddr.contains(":")) {
addr = cashAddr.split(":").last;
}
return addr.startsWith("q");
}
@override @override
bool validateAddress(String address) { bool validateAddress(String address) {
try { try {
@ -1217,12 +1233,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
} }
if (format == bitbox.Address.formatCashAddr) { if (format == bitbox.Address.formatCashAddr) {
String addr = address; return validateCashAddr(address);
if (address.contains(":")) {
addr = address.split(":").last;
}
return addr.startsWith("q");
} else { } else {
return address.startsWith("1"); return address.startsWith("1");
} }
@ -2085,7 +2096,8 @@ class BitcoinCashWallet extends CoinServiceAPI {
String _convertToScriptHash(String bchAddress, NetworkType network) { String _convertToScriptHash(String bchAddress, NetworkType network) {
try { try {
if (bitbox.Address.detectFormat(bchAddress) == if (bitbox.Address.detectFormat(bchAddress) ==
bitbox.Address.formatCashAddr) { bitbox.Address.formatCashAddr &&
validateCashAddr(bchAddress)) {
bchAddress = bitbox.Address.toLegacyAddress(bchAddress); bchAddress = bitbox.Address.toLegacyAddress(bchAddress);
} }
final output = Address.addressToOutputScript(bchAddress, network); final output = Address.addressToOutputScript(bchAddress, network);
@ -2163,7 +2175,8 @@ class BitcoinCashWallet extends CoinServiceAPI {
List<String> allAddressesOld = await _fetchAllOwnAddresses(); List<String> allAddressesOld = await _fetchAllOwnAddresses();
List<String> allAddresses = []; List<String> allAddresses = [];
for (String address in allAddressesOld) { for (String address in allAddressesOld) {
if (bitbox.Address.detectFormat(address) == bitbox.Address.formatLegacy) { if (bitbox.Address.detectFormat(address) == bitbox.Address.formatLegacy &&
addressType(address: address) == DerivePathType.bip44) {
allAddresses.add(bitbox.Address.toCashAddress(address)); allAddresses.add(bitbox.Address.toCashAddress(address));
} else { } else {
allAddresses.add(address); allAddresses.add(address);
@ -2882,7 +2895,12 @@ class BitcoinCashWallet extends CoinServiceAPI {
String address = output["scriptPubKey"]["addresses"][0] as String; String address = output["scriptPubKey"]["addresses"][0] as String;
if (bitbox.Address.detectFormat(address) == if (bitbox.Address.detectFormat(address) ==
bitbox.Address.formatCashAddr) { bitbox.Address.formatCashAddr) {
address = bitbox.Address.toLegacyAddress(address); if (validateCashAddr(address)) {
address = bitbox.Address.toLegacyAddress(address);
} else {
throw Exception(
"Unsupported address found during fetchBuildTxData(): $address");
}
} }
if (!addressTxid.containsKey(address)) { if (!addressTxid.containsKey(address)) {
addressTxid[address] = <String>[]; addressTxid[address] = <String>[];
@ -2913,10 +2931,6 @@ class BitcoinCashWallet extends CoinServiceAPI {
); );
for (int i = 0; i < p2pkhLength; i++) { for (int i = 0; i < p2pkhLength; i++) {
String address = addressesP2PKH[i]; String address = addressesP2PKH[i];
if (bitbox.Address.detectFormat(address) ==
bitbox.Address.formatCashAddr) {
address = bitbox.Address.toLegacyAddress(address);
}
// receives // receives
final receiveDerivation = receiveDerivations[address]; final receiveDerivation = receiveDerivations[address];

View file

@ -60,7 +60,7 @@ void main() {
}); });
}); });
group("validate mainnet bitcoincash addresses", () { group("mainnet bitcoincash addressType", () {
MockElectrumX? client; MockElectrumX? client;
MockCachedElectrumX? cachedClient; MockCachedElectrumX? cachedClient;
MockPriceAPI? priceAPI; MockPriceAPI? priceAPI;
@ -136,6 +136,168 @@ void main() {
verifyNoMoreInteractions(priceAPI); verifyNoMoreInteractions(priceAPI);
}); });
test("P2PKH cashaddr with prefix", () {
expect(
mainnetWallet?.addressType(
address:
"bitcoincash:qrwjyc4pewj9utzrtnh0whkzkuvy5q8wg52n254x6k"),
DerivePathType.bip44);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("P2PKH cashaddr without prefix", () {
expect(
mainnetWallet?.addressType(
address: "qrwjyc4pewj9utzrtnh0whkzkuvy5q8wg52n254x6k"),
DerivePathType.bip44);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("Multisig cashaddr with prefix", () {
expect(
() => mainnetWallet?.addressType(
address:
"bitcoincash:pzpp3nchmzzf0gr69lj82ymurg5u3ds6kcwr5m07np"),
throwsArgumentError);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("Multisig cashaddr without prefix", () {
expect(
() => mainnetWallet?.addressType(
address: "pzpp3nchmzzf0gr69lj82ymurg5u3ds6kcwr5m07np"),
throwsArgumentError);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("Multisig/P2SH address", () {
expect(
mainnetWallet?.addressType(
address: "3DYuVEmuKWQFxJcF7jDPhwPiXLTiNnyMFb"),
DerivePathType.bip49);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
});
group("validate mainnet bitcoincash addresses", () {
MockElectrumX? client;
MockCachedElectrumX? cachedClient;
MockPriceAPI? priceAPI;
FakeSecureStorage? secureStore;
MockTransactionNotificationTracker? tracker;
BitcoinCashWallet? mainnetWallet;
setUp(() {
client = MockElectrumX();
cachedClient = MockCachedElectrumX();
priceAPI = MockPriceAPI();
secureStore = FakeSecureStorage();
tracker = MockTransactionNotificationTracker();
mainnetWallet = BitcoinCashWallet(
walletId: "validateAddressMainNet",
walletName: "validateAddressMainNet",
coin: Coin.bitcoincash,
client: client!,
cachedClient: cachedClient!,
tracker: tracker!,
priceAPI: priceAPI,
secureStore: secureStore,
);
});
test("valid mainnet legacy/p2pkh address type", () {
expect(
mainnetWallet?.validateAddress("1DP3PUePwMa5CoZwzjznVKhzdLsZftjcAT"),
true);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("valid mainnet legacy/p2pkh cashaddr with prefix address type", () {
expect(
mainnetWallet?.validateAddress(
"bitcoincash:qrwjyc4pewj9utzrtnh0whkzkuvy5q8wg52n254x6k"),
true);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("valid mainnet legacy/p2pkh cashaddr without prefix address type", () {
expect(
mainnetWallet
?.validateAddress("qrwjyc4pewj9utzrtnh0whkzkuvy5q8wg52n254x6k"),
true);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("invalid legacy/p2pkh address type", () {
expect(
mainnetWallet?.validateAddress("mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"),
false);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test(
"invalid cashaddr (is valid multisig but bitbox is broken for multisig)",
() {
expect(
mainnetWallet
?.validateAddress("pzpp3nchmzzf0gr69lj82ymurg5u3ds6kcwr5m07np"),
false);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("multisig address should fail for bitbox", () {
expect(
mainnetWallet?.validateAddress("3DYuVEmuKWQFxJcF7jDPhwPiXLTiNnyMFb"),
false);
expect(secureStore?.interactions, 0);
verifyNoMoreInteractions(client);
verifyNoMoreInteractions(cachedClient);
verifyNoMoreInteractions(tracker);
verifyNoMoreInteractions(priceAPI);
});
test("invalid mainnet bitcoincash legacy/p2pkh address", () { test("invalid mainnet bitcoincash legacy/p2pkh address", () {
expect( expect(
mainnetWallet?.validateAddress("mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"), mainnetWallet?.validateAddress("mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"),