diff --git a/lib/db/main_db.dart b/lib/db/main_db.dart index be6a98089..a886dcf06 100644 --- a/lib/db/main_db.dart +++ b/lib/db/main_db.dart @@ -42,6 +42,17 @@ class MainDB { await isar.addresses.putAll(addresses); }); + Future updateAddress(Address oldAddress, Address newAddress) => + isar.writeTxn(() async { + newAddress.id = oldAddress.id; + await oldAddress.transaction.load(); + final txns = oldAddress.transaction.toList(); + await isar.addresses.delete(oldAddress.id); + await isar.addresses.put(newAddress); + newAddress.transaction.addAll(txns); + await newAddress.transaction.save(); + }); + // transactions QueryBuilder getTransactions( String walletId) => diff --git a/lib/services/coins/bitcoin/bitcoin_wallet.dart b/lib/services/coins/bitcoin/bitcoin_wallet.dart index e5a500a40..f0ca06915 100644 --- a/lib/services/coins/bitcoin/bitcoin_wallet.dart +++ b/lib/services/coins/bitcoin/bitcoin_wallet.dart @@ -1859,8 +1859,23 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain( 0, newReceivingIndex, DerivePathType.bip84); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } catch (e, s) { Logging.instance.log( @@ -1886,8 +1901,23 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newChangeAddress = await _generateAddressForChain( 1, newChangeIndex, DerivePathType.bip84); - // Add that new change address - await db.putAddress(newChangeAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newChangeAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newChangeAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newChangeAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkChangeAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( diff --git a/lib/services/coins/bitcoincash/bitcoincash_wallet.dart b/lib/services/coins/bitcoincash/bitcoincash_wallet.dart index df1fe4128..b3fc5b4b5 100644 --- a/lib/services/coins/bitcoincash/bitcoincash_wallet.dart +++ b/lib/services/coins/bitcoincash/bitcoincash_wallet.dart @@ -1746,8 +1746,23 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain( 0, newReceivingIndex, DerivePathType.bip44); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( @@ -1778,8 +1793,23 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB { final newChangeAddress = await _generateAddressForChain( 1, newChangeIndex, DerivePathType.bip44); - // Add that new change address - await db.putAddress(newChangeAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newChangeAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newChangeAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newChangeAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkChangeAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( diff --git a/lib/services/coins/dogecoin/dogecoin_wallet.dart b/lib/services/coins/dogecoin/dogecoin_wallet.dart index 4ce4fe1f6..bc799530a 100644 --- a/lib/services/coins/dogecoin/dogecoin_wallet.dart +++ b/lib/services/coins/dogecoin/dogecoin_wallet.dart @@ -1650,8 +1650,23 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain( 0, newReceivingIndex, DerivePathType.bip44); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( @@ -1682,8 +1697,23 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newChangeAddress = await _generateAddressForChain( 1, newChangeIndex, DerivePathType.bip44); - // Add that new change address - await db.putAddress(newChangeAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newChangeAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newChangeAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newChangeAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await checkChangeAddressForTransactions(); + } } } catch (e, s) { Logging.instance.log( diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index 9a587b12e..b679f203f 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -3147,8 +3147,23 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive { newReceivingIndex, ); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await checkReceivingAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( @@ -3182,8 +3197,23 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive { newChangeIndex, ); - // Add that new change address - await db.putAddress(newChangeAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newChangeAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newChangeAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newChangeAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await checkChangeAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( diff --git a/lib/services/coins/litecoin/litecoin_wallet.dart b/lib/services/coins/litecoin/litecoin_wallet.dart index 62b7c4232..7604d3811 100644 --- a/lib/services/coins/litecoin/litecoin_wallet.dart +++ b/lib/services/coins/litecoin/litecoin_wallet.dart @@ -1885,8 +1885,23 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain( 0, newReceivingIndex, DerivePathType.bip84); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } catch (e, s) { Logging.instance.log( @@ -1912,8 +1927,23 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newChangeAddress = await _generateAddressForChain( 1, newChangeIndex, DerivePathType.bip84); - // Add that new change address - await db.putAddress(newChangeAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newChangeAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newChangeAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newChangeAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkChangeAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( diff --git a/lib/services/coins/monero/monero_wallet.dart b/lib/services/coins/monero/monero_wallet.dart index 538488bfa..663e5fe34 100644 --- a/lib/services/coins/monero/monero_wallet.dart +++ b/lib/services/coins/monero/monero_wallet.dart @@ -1131,8 +1131,23 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain(0, newReceivingIndex); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( diff --git a/lib/services/coins/namecoin/namecoin_wallet.dart b/lib/services/coins/namecoin/namecoin_wallet.dart index 2995ea441..fe064fe7f 100644 --- a/lib/services/coins/namecoin/namecoin_wallet.dart +++ b/lib/services/coins/namecoin/namecoin_wallet.dart @@ -1867,8 +1867,23 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain( 0, newReceivingIndex, DerivePathType.bip84); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } catch (e, s) { Logging.instance.log( @@ -1894,8 +1909,23 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB { final newChangeAddress = await _generateAddressForChain( 1, newChangeIndex, DerivePathType.bip84); - // Add that new change address - await db.putAddress(newChangeAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newChangeAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newChangeAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newChangeAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkChangeAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( diff --git a/lib/services/coins/particl/particl_wallet.dart b/lib/services/coins/particl/particl_wallet.dart index 1dba3b144..59e9e718e 100644 --- a/lib/services/coins/particl/particl_wallet.dart +++ b/lib/services/coins/particl/particl_wallet.dart @@ -1754,8 +1754,23 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain( 0, newReceivingIndex, DerivePathType.bip84); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } catch (e, s) { Logging.instance.log( @@ -1781,8 +1796,23 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB { final newChangeAddress = await _generateAddressForChain( 1, newChangeIndex, DerivePathType.bip84); - // Add that new change address - await db.putAddress(newChangeAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newChangeAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newChangeAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newChangeAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkChangeAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log( diff --git a/lib/services/coins/wownero/wownero_wallet.dart b/lib/services/coins/wownero/wownero_wallet.dart index f864d44e0..6c2dfcbb7 100644 --- a/lib/services/coins/wownero/wownero_wallet.dart +++ b/lib/services/coins/wownero/wownero_wallet.dart @@ -1200,8 +1200,23 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB { final newReceivingAddress = await _generateAddressForChain(0, newReceivingIndex); - // Add that new receiving address - await db.putAddress(newReceivingAddress); + final existing = await db + .getAddresses(walletId) + .filter() + .valueEqualTo(newReceivingAddress.value) + .findFirst(); + if (existing == null) { + // Add that new change address + await db.putAddress(newReceivingAddress); + } else { + // we need to update the address + await db.updateAddress(existing, newReceivingAddress); + + // since we updated an existing address there is a chance it has + // some tx history. To prevent address reuse we will call check again + // recursively + await _checkReceivingAddressForTransactions(); + } } } on SocketException catch (se, s) { Logging.instance.log(