subaddress fix (#1620)
* subaddress fix * fix subaddress generation * rewrite usedAddresses for xmr and wow * [skip ci] remove print statements
cyan committed
Aug 27, 2024 at 01:40 UTC
4c795ea5c26f2b5ba88317cf6d02fd284bc420fb
8 files changed
+99
-13
cw_monero/lib/api/transaction_history.dart
+22
-5
@@ -45,6 +45,8 @@ List<Transaction> getAllTransactions() {
45
confirmations: 0,
46
blockheight: 0,
47
accountIndex: i,
48
+ addressIndex: 0,
49
+ addressIndexList: [0],
50
paymentId: "",
51
amount: fullBalance - availBalance,
52
isSpend: false,
@@ -245,19 +247,30 @@ Future<PendingTransactionDescription> createTransactionMultDest(
247
248
class Transaction {
249
final String displayLabel;
248
- String subaddressLabel = monero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0);
249
- late final String address = monero.Wallet_address(
250
+ String get subaddressLabel => monero.Wallet_getSubaddressLabel(
251
wptr!,
251
- accountIndex: 0,
252
- addressIndex: 0,
252
+ accountIndex: accountIndex,
253
+ addressIndex: addressIndex,
254
);
255
+ String get address => monero.Wallet_address(
256
+ wptr!,
257
+ accountIndex: accountIndex,
258
+ addressIndex: addressIndex,
259
+ );
260
+ List<String> get addressList => List.generate(addressIndexList.length, (index) =>
261
+ monero.Wallet_address(
262
+ wptr!,
263
+ accountIndex: accountIndex,
264
+ addressIndex: addressIndexList[index],
265
+ ));
266
final String description;
267
final int fee;
268
final int confirmations;
269
late final bool isPending = confirmations < 10;
270
final int blockheight;
259
- final int addressIndex = 0;
271
+ final int addressIndex;
272
final int accountIndex;
273
+ final List<int> addressIndexList;
274
final String paymentId;
275
final int amount;
276
final bool isSpend;
@@ -303,6 +316,8 @@ class Transaction {
316
amount = monero.TransactionInfo_amount(txInfo),
317
paymentId = monero.TransactionInfo_paymentId(txInfo),
318
accountIndex = monero.TransactionInfo_subaddrAccount(txInfo),
319
+ addressIndex = int.tryParse(monero.TransactionInfo_subaddrIndex(txInfo).split(", ")[0]) ?? 0,
320
+ addressIndexList = monero.TransactionInfo_subaddrIndex(txInfo).split(", ").map((e) => int.tryParse(e) ?? 0).toList(),
321
blockheight = monero.TransactionInfo_blockHeight(txInfo),
322
confirmations = monero.TransactionInfo_confirmations(txInfo),
323
fee = monero.TransactionInfo_fee(txInfo),
@@ -316,6 +331,8 @@ class Transaction {
331
required this.confirmations,
332
required this.blockheight,
333
required this.accountIndex,
334
+ required this.addressIndexList,
335
+ required this.addressIndex,
336
required this.paymentId,
337
required this.amount,
338
required this.isSpend,
cw_monero/lib/monero_subaddress_list.dart
+6
-3
@@ -1,6 +1,7 @@
1
import 'package:cw_core/subaddress.dart';
2
import 'package:cw_monero/api/coins_info.dart';
3
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
4
+import 'package:cw_monero/api/wallet.dart';
5
import 'package:flutter/services.dart';
6
import 'package:mobx/mobx.dart';
7
@@ -103,6 +104,9 @@ abstract class MoneroSubaddressListBase with Store {
104
required List<String> usedAddresses,
105
}) async {
106
_usedAddresses.addAll(usedAddresses);
107
+ final _all = _usedAddresses.toSet().toList();
108
+ _usedAddresses.clear();
109
+ _usedAddresses.addAll(_all);
110
if (_isUpdating) {
111
return;
112
}
@@ -124,7 +128,7 @@ abstract class MoneroSubaddressListBase with Store {
128
Future<List<Subaddress>> _getAllUnusedAddresses(
129
{required int accountIndex, required String label}) async {
130
final allAddresses = subaddress_list.getAllSubaddresses();
127
- if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.last)) {
131
+ if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.first.address)) {
132
final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label);
133
if (!isAddressUnused) {
134
return await _getAllUnusedAddresses(accountIndex: accountIndex, label: label);
@@ -143,8 +147,7 @@ abstract class MoneroSubaddressListBase with Store {
147
label.toLowerCase() == 'Primary account'.toLowerCase()
148
? 'Primary address'
149
: label);
146
- })
147
- .toList();
150
+ }).toList().reversed.toList();
151
}
152
153
Future<bool> _newSubaddress({required int accountIndex, required String label}) async {
cw_monero/lib/monero_wallet.dart
+5
@@ -88,6 +88,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
88
reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
89
_updateSubAddress(enabled, account: walletAddresses.account);
90
});
91
+ reaction((_) => transactionHistory, (__) {
92
+ _updateSubAddress(isEnabledAutoGenerateSubaddress, account: walletAddresses.account);
93
+ });
94
}
95
96
static const int _autoSaveInterval = 30;
@@ -130,6 +133,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
133
134
monero_wallet.SyncListener? _listener;
135
ReactionDisposer? _onAccountChangeReaction;
136
+ ReactionDisposer? _onTxHistoryChangeReaction;
137
bool _isTransactionUpdating;
138
bool _hasSyncAfterStartup;
139
Timer? _autoSaveTimer;
@@ -169,6 +173,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
173
void close() async {
174
_listener?.stop();
175
_onAccountChangeReaction?.reaction.dispose();
176
+ _onTxHistoryChangeReaction?.reaction.dispose();
177
_autoSaveTimer?.cancel();
178
}
179
cw_monero/lib/monero_wallet_addresses.dart
+20
@@ -3,6 +3,7 @@ import 'package:cw_core/address_info.dart';
3
import 'package:cw_core/subaddress.dart';
4
import 'package:cw_core/wallet_addresses.dart';
5
import 'package:cw_core/wallet_info.dart';
6
+import 'package:cw_monero/api/transaction_history.dart';
7
import 'package:cw_monero/api/wallet.dart';
8
import 'package:cw_monero/monero_account_list.dart';
9
import 'package:cw_monero/monero_subaddress_list.dart';
@@ -37,6 +38,25 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
38
39
MoneroAccountList accountList;
40
41
+ @override
42
+ Set<String> get usedAddresses {
43
+ final txs = getAllTransactions();
44
+ final adds = _originalUsedAddresses.toList();
45
+ for (var i = 0; i < txs.length; i++) {
46
+ for (var j = 0; j < txs[i].addressList.length; j++) {
47
+ adds.add(txs[i].addressList[j]);
48
+ }
49
+ }
50
+ return adds.toSet();
51
+ }
52
+
53
+ Set<String> _originalUsedAddresses = Set();
54
+
55
+ @override
56
+ set usedAddresses(Set<String> _usedAddresses) {
57
+ _originalUsedAddresses = _usedAddresses;
58
+ }
59
+
60
@override
61
Future<void> init() async {
62
accountList.update();
cw_wownero/lib/api/transaction_history.dart
+18
-5
@@ -45,6 +45,8 @@ List<Transaction> getAllTransactions() {
45
confirmations: 0,
46
blockheight: 0,
47
accountIndex: i,
48
+ addressIndex: 0,
49
+ addressIndexList: [0],
50
paymentId: "",
51
amount: fullBalance - availBalance,
52
isSpend: false,
@@ -243,19 +245,26 @@ Future<PendingTransactionDescription> createTransactionMultDest(
245
246
class Transaction {
247
final String displayLabel;
246
- String subaddressLabel = wownero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0);
247
- late final String address = wownero.Wallet_address(
248
+ String get subaddressLabel => wownero.Wallet_getSubaddressLabel(wptr!, accountIndex: 0, addressIndex: 0);
249
+ String get address => wownero.Wallet_address(
250
wptr!,
249
- accountIndex: 0,
250
- addressIndex: 0,
251
+ accountIndex: accountIndex,
252
+ addressIndex: addressIndex,
253
);
254
+ List<String> get addressList => List.generate(addressIndexList.length, (index) =>
255
+ wownero.Wallet_address(
256
+ wptr!,
257
+ accountIndex: accountIndex,
258
+ addressIndex: addressIndexList[index],
259
+ ));
260
final String description;
261
final int fee;
262
final int confirmations;
263
late final bool isPending = confirmations < 3;
264
final int blockheight;
257
- final int addressIndex = 0;
265
+ final int addressIndex;
266
final int accountIndex;
267
+ final List<int> addressIndexList;
268
final String paymentId;
269
final int amount;
270
final bool isSpend;
@@ -301,6 +310,8 @@ class Transaction {
310
amount = wownero.TransactionInfo_amount(txInfo),
311
paymentId = wownero.TransactionInfo_paymentId(txInfo),
312
accountIndex = wownero.TransactionInfo_subaddrAccount(txInfo),
313
+ addressIndex = int.tryParse(wownero.TransactionInfo_subaddrIndex(txInfo).split(", ")[0]) ?? 0,
314
+ addressIndexList = wownero.TransactionInfo_subaddrIndex(txInfo).split(", ").map((e) => int.tryParse(e) ?? 0).toList(),
315
blockheight = wownero.TransactionInfo_blockHeight(txInfo),
316
confirmations = wownero.TransactionInfo_confirmations(txInfo),
317
fee = wownero.TransactionInfo_fee(txInfo),
@@ -314,6 +325,8 @@ class Transaction {
325
required this.confirmations,
326
required this.blockheight,
327
required this.accountIndex,
328
+ required this.addressIndex,
329
+ required this.addressIndexList,
330
required this.paymentId,
331
required this.amount,
332
required this.isSpend,
cw_wownero/lib/wownero_subaddress_list.dart
+4
@@ -1,6 +1,7 @@
1
import 'package:cw_core/subaddress.dart';
2
import 'package:cw_wownero/api/coins_info.dart';
3
import 'package:cw_wownero/api/subaddress_list.dart' as subaddress_list;
4
+import 'package:cw_wownero/api/wallet.dart';
5
import 'package:flutter/services.dart';
6
import 'package:mobx/mobx.dart';
7
@@ -103,6 +104,9 @@ abstract class WowneroSubaddressListBase with Store {
104
required List<String> usedAddresses,
105
}) async {
106
_usedAddresses.addAll(usedAddresses);
107
+ final _all = _usedAddresses.toSet().toList();
108
+ _usedAddresses.clear();
109
+ _usedAddresses.addAll(_all);
110
if (_isUpdating) {
111
return;
112
}
cw_wownero/lib/wownero_wallet.dart
+6
@@ -82,6 +82,10 @@ abstract class WowneroWalletBase
82
reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
83
_updateSubAddress(enabled, account: walletAddresses.account);
84
});
85
+
86
+ _onTxHistoryChangeReaction = reaction((_) => transactionHistory, (__) {
87
+ _updateSubAddress(isEnabledAutoGenerateSubaddress, account: walletAddresses.account);
88
+ });
89
}
90
91
static const int _autoSaveInterval = 30;
@@ -123,6 +127,7 @@ abstract class WowneroWalletBase
127
128
wownero_wallet.SyncListener? _listener;
129
ReactionDisposer? _onAccountChangeReaction;
130
+ ReactionDisposer? _onTxHistoryChangeReaction;
131
bool _isTransactionUpdating;
132
bool _hasSyncAfterStartup;
133
Timer? _autoSaveTimer;
@@ -158,6 +163,7 @@ abstract class WowneroWalletBase
163
void close() async {
164
_listener?.stop();
165
_onAccountChangeReaction?.reaction.dispose();
166
+ _onTxHistoryChangeReaction?.reaction.dispose();
167
_autoSaveTimer?.cancel();
168
}
169
cw_wownero/lib/wownero_wallet_addresses.dart
+18
@@ -3,6 +3,7 @@ import 'package:cw_core/address_info.dart';
3
import 'package:cw_core/subaddress.dart';
4
import 'package:cw_core/wallet_addresses.dart';
5
import 'package:cw_core/wallet_info.dart';
6
+import 'package:cw_wownero/api/transaction_history.dart';
7
import 'package:cw_wownero/api/wallet.dart';
8
import 'package:cw_wownero/wownero_account_list.dart';
9
import 'package:cw_wownero/wownero_subaddress_list.dart';
@@ -36,7 +37,24 @@ abstract class WowneroWalletAddressesBase extends WalletAddresses with Store {
37
WowneroSubaddressList subaddressList;
38
39
WowneroAccountList accountList;
40
+ @override
41
+ Set<String> get usedAddresses {
42
+ final txs = getAllTransactions();
43
+ final adds = _originalUsedAddresses.toList();
44
+ for (var i = 0; i < txs.length; i++) {
45
+ for (var j = 0; j < txs[i].addressList.length; j++) {
46
+ adds.add(txs[i].addressList[j]);
47
+ }
48
+ }
49
+ return adds.toSet();
50
+ }
51
52
+ Set<String> _originalUsedAddresses = Set();
53
+
54
+ @override
55
+ set usedAddresses(Set<String> _usedAddresses) {
56
+ _originalUsedAddresses = _usedAddresses;
57
+ }
58
@override
59
Future<void> init() async {
60
accountList.update();