From 4c795ea5c26f2b5ba88317cf6d02fd284bc420fb Mon Sep 17 00:00:00 2001 From: cyan Date: Tue, 27 Aug 2024 01:40:20 +0200 Subject: [PATCH] subaddress fix (#1620) * subaddress fix * fix subaddress generation * rewrite usedAddresses for xmr and wow * [skip ci] remove print statements --- cw_monero/lib/api/transaction_history.dart | 27 ++++++++++++++++---- cw_monero/lib/monero_subaddress_list.dart | 9 ++++--- cw_monero/lib/monero_wallet.dart | 5 ++++ cw_monero/lib/monero_wallet_addresses.dart | 20 +++++++++++++++ cw_wownero/lib/api/transaction_history.dart | 23 +++++++++++++---- cw_wownero/lib/wownero_subaddress_list.dart | 4 +++ cw_wownero/lib/wownero_wallet.dart | 6 +++++ cw_wownero/lib/wownero_wallet_addresses.dart | 18 +++++++++++++ 8 files changed, 99 insertions(+), 13 deletions(-) diff --git a/cw_monero/lib/api/transaction_history.dart b/cw_monero/lib/api/transaction_history.dart index b416e1b4eb..1f00b082fd 100644 --- a/cw_monero/lib/api/transaction_history.dart +++ b/cw_monero/lib/api/transaction_history.dart @@ -45,6 +45,8 @@ List getAllTransactions() { confirmations: 0, blockheight: 0, accountIndex: i, + addressIndex: 0, + addressIndexList: [0], paymentId: "", amount: fullBalance - availBalance, isSpend: false, @@ -245,19 +247,30 @@ Future createTransactionMultDest( class Transaction { final String displayLabel; - String subaddressLabel = monero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0); - late final String address = monero.Wallet_address( + String get subaddressLabel => monero.Wallet_getSubaddressLabel( wptr!, - accountIndex: 0, - addressIndex: 0, + accountIndex: accountIndex, + addressIndex: addressIndex, ); + String get address => monero.Wallet_address( + wptr!, + accountIndex: accountIndex, + addressIndex: addressIndex, + ); + List get addressList => List.generate(addressIndexList.length, (index) => + monero.Wallet_address( + wptr!, + accountIndex: accountIndex, + addressIndex: addressIndexList[index], + )); final String description; final int fee; final int confirmations; late final bool isPending = confirmations < 10; final int blockheight; - final int addressIndex = 0; + final int addressIndex; final int accountIndex; + final List addressIndexList; final String paymentId; final int amount; final bool isSpend; @@ -303,6 +316,8 @@ class Transaction { amount = monero.TransactionInfo_amount(txInfo), paymentId = monero.TransactionInfo_paymentId(txInfo), accountIndex = monero.TransactionInfo_subaddrAccount(txInfo), + addressIndex = int.tryParse(monero.TransactionInfo_subaddrIndex(txInfo).split(", ")[0]) ?? 0, + addressIndexList = monero.TransactionInfo_subaddrIndex(txInfo).split(", ").map((e) => int.tryParse(e) ?? 0).toList(), blockheight = monero.TransactionInfo_blockHeight(txInfo), confirmations = monero.TransactionInfo_confirmations(txInfo), fee = monero.TransactionInfo_fee(txInfo), @@ -316,6 +331,8 @@ class Transaction { required this.confirmations, required this.blockheight, required this.accountIndex, + required this.addressIndexList, + required this.addressIndex, required this.paymentId, required this.amount, required this.isSpend, diff --git a/cw_monero/lib/monero_subaddress_list.dart b/cw_monero/lib/monero_subaddress_list.dart index c35afb2824..fe85bef3b8 100644 --- a/cw_monero/lib/monero_subaddress_list.dart +++ b/cw_monero/lib/monero_subaddress_list.dart @@ -1,6 +1,7 @@ import 'package:cw_core/subaddress.dart'; import 'package:cw_monero/api/coins_info.dart'; import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list; +import 'package:cw_monero/api/wallet.dart'; import 'package:flutter/services.dart'; import 'package:mobx/mobx.dart'; @@ -103,6 +104,9 @@ abstract class MoneroSubaddressListBase with Store { required List usedAddresses, }) async { _usedAddresses.addAll(usedAddresses); + final _all = _usedAddresses.toSet().toList(); + _usedAddresses.clear(); + _usedAddresses.addAll(_all); if (_isUpdating) { return; } @@ -124,7 +128,7 @@ abstract class MoneroSubaddressListBase with Store { Future> _getAllUnusedAddresses( {required int accountIndex, required String label}) async { final allAddresses = subaddress_list.getAllSubaddresses(); - if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.last)) { + if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.first.address)) { final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label); if (!isAddressUnused) { return await _getAllUnusedAddresses(accountIndex: accountIndex, label: label); @@ -143,8 +147,7 @@ abstract class MoneroSubaddressListBase with Store { label.toLowerCase() == 'Primary account'.toLowerCase() ? 'Primary address' : label); - }) - .toList(); + }).toList().reversed.toList(); } Future _newSubaddress({required int accountIndex, required String label}) async { diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index f5fa0ec7e3..483ee88681 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -88,6 +88,9 @@ abstract class MoneroWalletBase extends WalletBase isEnabledAutoGenerateSubaddress, (bool enabled) { _updateSubAddress(enabled, account: walletAddresses.account); }); + reaction((_) => transactionHistory, (__) { + _updateSubAddress(isEnabledAutoGenerateSubaddress, account: walletAddresses.account); + }); } static const int _autoSaveInterval = 30; @@ -130,6 +133,7 @@ abstract class MoneroWalletBase extends WalletBase get usedAddresses { + final txs = getAllTransactions(); + final adds = _originalUsedAddresses.toList(); + for (var i = 0; i < txs.length; i++) { + for (var j = 0; j < txs[i].addressList.length; j++) { + adds.add(txs[i].addressList[j]); + } + } + return adds.toSet(); + } + + Set _originalUsedAddresses = Set(); + + @override + set usedAddresses(Set _usedAddresses) { + _originalUsedAddresses = _usedAddresses; + } + @override Future init() async { accountList.update(); diff --git a/cw_wownero/lib/api/transaction_history.dart b/cw_wownero/lib/api/transaction_history.dart index a1e1e3c9b6..020c47df63 100644 --- a/cw_wownero/lib/api/transaction_history.dart +++ b/cw_wownero/lib/api/transaction_history.dart @@ -45,6 +45,8 @@ List getAllTransactions() { confirmations: 0, blockheight: 0, accountIndex: i, + addressIndex: 0, + addressIndexList: [0], paymentId: "", amount: fullBalance - availBalance, isSpend: false, @@ -243,19 +245,26 @@ Future createTransactionMultDest( class Transaction { final String displayLabel; - String subaddressLabel = wownero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0); - late final String address = wownero.Wallet_address( + String get subaddressLabel => wownero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0); + String get address => wownero.Wallet_address( wptr!, - accountIndex: 0, - addressIndex: 0, + accountIndex: accountIndex, + addressIndex: addressIndex, ); + List get addressList => List.generate(addressIndexList.length, (index) => + wownero.Wallet_address( + wptr!, + accountIndex: accountIndex, + addressIndex: addressIndexList[index], + )); final String description; final int fee; final int confirmations; late final bool isPending = confirmations < 3; final int blockheight; - final int addressIndex = 0; + final int addressIndex; final int accountIndex; + final List addressIndexList; final String paymentId; final int amount; final bool isSpend; @@ -301,6 +310,8 @@ class Transaction { amount = wownero.TransactionInfo_amount(txInfo), paymentId = wownero.TransactionInfo_paymentId(txInfo), accountIndex = wownero.TransactionInfo_subaddrAccount(txInfo), + addressIndex = int.tryParse(wownero.TransactionInfo_subaddrIndex(txInfo).split(", ")[0]) ?? 0, + addressIndexList = wownero.TransactionInfo_subaddrIndex(txInfo).split(", ").map((e) => int.tryParse(e) ?? 0).toList(), blockheight = wownero.TransactionInfo_blockHeight(txInfo), confirmations = wownero.TransactionInfo_confirmations(txInfo), fee = wownero.TransactionInfo_fee(txInfo), @@ -314,6 +325,8 @@ class Transaction { required this.confirmations, required this.blockheight, required this.accountIndex, + required this.addressIndex, + required this.addressIndexList, required this.paymentId, required this.amount, required this.isSpend, diff --git a/cw_wownero/lib/wownero_subaddress_list.dart b/cw_wownero/lib/wownero_subaddress_list.dart index 61fd09ef99..5c026cc86e 100644 --- a/cw_wownero/lib/wownero_subaddress_list.dart +++ b/cw_wownero/lib/wownero_subaddress_list.dart @@ -1,6 +1,7 @@ import 'package:cw_core/subaddress.dart'; import 'package:cw_wownero/api/coins_info.dart'; import 'package:cw_wownero/api/subaddress_list.dart' as subaddress_list; +import 'package:cw_wownero/api/wallet.dart'; import 'package:flutter/services.dart'; import 'package:mobx/mobx.dart'; @@ -103,6 +104,9 @@ abstract class WowneroSubaddressListBase with Store { required List usedAddresses, }) async { _usedAddresses.addAll(usedAddresses); + final _all = _usedAddresses.toSet().toList(); + _usedAddresses.clear(); + _usedAddresses.addAll(_all); if (_isUpdating) { return; } diff --git a/cw_wownero/lib/wownero_wallet.dart b/cw_wownero/lib/wownero_wallet.dart index c3f4bcb69d..ab7691dd6e 100644 --- a/cw_wownero/lib/wownero_wallet.dart +++ b/cw_wownero/lib/wownero_wallet.dart @@ -82,6 +82,10 @@ abstract class WowneroWalletBase reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) { _updateSubAddress(enabled, account: walletAddresses.account); }); + + _onTxHistoryChangeReaction = reaction((_) => transactionHistory, (__) { + _updateSubAddress(isEnabledAutoGenerateSubaddress, account: walletAddresses.account); + }); } static const int _autoSaveInterval = 30; @@ -123,6 +127,7 @@ abstract class WowneroWalletBase wownero_wallet.SyncListener? _listener; ReactionDisposer? _onAccountChangeReaction; + ReactionDisposer? _onTxHistoryChangeReaction; bool _isTransactionUpdating; bool _hasSyncAfterStartup; Timer? _autoSaveTimer; @@ -158,6 +163,7 @@ abstract class WowneroWalletBase void close() async { _listener?.stop(); _onAccountChangeReaction?.reaction.dispose(); + _onTxHistoryChangeReaction?.reaction.dispose(); _autoSaveTimer?.cancel(); } diff --git a/cw_wownero/lib/wownero_wallet_addresses.dart b/cw_wownero/lib/wownero_wallet_addresses.dart index 9eeb182ebe..b36c0e9ec2 100644 --- a/cw_wownero/lib/wownero_wallet_addresses.dart +++ b/cw_wownero/lib/wownero_wallet_addresses.dart @@ -3,6 +3,7 @@ import 'package:cw_core/address_info.dart'; import 'package:cw_core/subaddress.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; +import 'package:cw_wownero/api/transaction_history.dart'; import 'package:cw_wownero/api/wallet.dart'; import 'package:cw_wownero/wownero_account_list.dart'; import 'package:cw_wownero/wownero_subaddress_list.dart'; @@ -36,7 +37,24 @@ abstract class WowneroWalletAddressesBase extends WalletAddresses with Store { WowneroSubaddressList subaddressList; WowneroAccountList accountList; + @override + Set get usedAddresses { + final txs = getAllTransactions(); + final adds = _originalUsedAddresses.toList(); + for (var i = 0; i < txs.length; i++) { + for (var j = 0; j < txs[i].addressList.length; j++) { + adds.add(txs[i].addressList[j]); + } + } + return adds.toSet(); + } + Set _originalUsedAddresses = Set(); + + @override + set usedAddresses(Set _usedAddresses) { + _originalUsedAddresses = _usedAddresses; + } @override Future init() async { accountList.update();