fix(cw_monero): prevent monero wallet from breaking during rename (#2214)
* fix(cw_monero): prevent monero wallet from breaking during rename * update to cleaned up monero.dart * fix: transaction screen not refreshing in monero * fix: wallets not opening until app restart after rename. * fix(cw_decred): wallet renaming throwing * fix: transaction not being shown after sending until 1st confirmation * fix(cw_monero): loop safeguard * fix: don't await wallet.fetchTransactions
cyan committed
May 2, 2025 at 14:30 UTC
a2294c4a061c40194223600a12aabacca3b15bc4
25 files changed
+578
-715
cw_decred/lib/wallet.dart
+20
-1
@@ -1,6 +1,7 @@
1
import 'dart:async';
2
import 'dart:convert';
3
import 'dart:io';
4
+import 'package:path/path.dart' as p;
5
import 'package:cw_core/exceptions.dart';
6
import 'package:cw_core/transaction_direction.dart';
7
import 'package:cw_core/utils/print_verbose.dart';
@@ -602,7 +603,25 @@ abstract class DecredWalletBase
603
throw "wallet already exists at $newDirPath";
604
}
605
605
- await Directory(currentDirPath).rename(newDirPath);
606
+ final sourceDir = Directory(currentDirPath);
607
+ final targetDir = Directory(newDirPath);
608
+
609
+ if (!targetDir.existsSync()) {
610
+ await targetDir.create(recursive: true);
611
+ }
612
+
613
+ await for (final entity in sourceDir.list(recursive: true)) {
614
+ final relativePath = entity.path.substring(sourceDir.path.length+1);
615
+ final targetPath = p.join(targetDir.path, relativePath);
616
+
617
+ if (entity is File) {
618
+ await entity.rename(targetPath);
619
+ } else if (entity is Directory) {
620
+ await Directory(targetPath).create(recursive: true);
621
+ }
622
+ }
623
+
624
+ await sourceDir.delete(recursive: true);
625
}
626
627
@override
cw_decred/lib/wallet_service.dart
+4
@@ -118,6 +118,10 @@ class DecredWalletService extends WalletService<
118
currentWalletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
119
? testnet
120
: mainnet;
121
+ if (libwallet == null) {
122
+ libwallet = await Libwallet.spawn();
123
+ libwallet!.initLibdcrwallet("", "err");
124
+ }
125
final currentWallet = DecredWallet(
126
currentWalletInfo, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
127
cw_monero/lib/api/account_list.dart
+23
-40
@@ -2,31 +2,31 @@ import 'dart:async';
2
3
import 'package:cw_monero/api/wallet.dart';
4
import 'package:cw_monero/monero_account_list.dart';
5
-import 'package:monero/monero.dart' as monero;
5
+import 'package:monero/src/wallet2.dart';
6
+import 'package:monero/src/monero.dart';
7
7
-monero.wallet? wptr = null;
8
-bool get isViewOnly => int.tryParse(monero.Wallet_secretSpendKey(wptr!)) == 0;
8
+Wallet2Wallet? currentWallet = null;
9
+bool get isViewOnly => int.tryParse(currentWallet!.secretSpendKey()) == 0;
10
11
int _wlptrForW = 0;
11
-monero.WalletListener? _wlptr = null;
12
+Wallet2WalletListener? _wlptr = null;
13
13
-monero.WalletListener? getWlptr() {
14
- if (wptr == null) return null;
15
- if (wptr!.address == _wlptrForW) return _wlptr!;
16
- _wlptrForW = wptr!.address;
17
- _wlptr = monero.MONERO_cw_getWalletListener(wptr!);
14
+Wallet2WalletListener? getWlptr() {
15
+ if (currentWallet == null) return null;
16
+ _wlptrForW = currentWallet!.ffiAddress();
17
+ _wlptr = currentWallet!.getWalletListener();
18
return _wlptr!;
19
}
20
21
-monero.SubaddressAccount? subaddressAccount;
21
+Wallet2SubaddressAccount? subaddressAccount;
22
23
bool isUpdating = false;
24
25
void refreshAccounts() {
26
try {
27
isUpdating = true;
28
- subaddressAccount = monero.Wallet_subaddressAccount(wptr!);
29
- monero.SubaddressAccount_refresh(subaddressAccount!);
28
+ subaddressAccount = currentWallet!.subaddressAccount();
29
+ subaddressAccount!.refresh();
30
isUpdating = false;
31
} catch (e) {
32
isUpdating = false;
@@ -34,45 +34,28 @@ void refreshAccounts() {
34
}
35
}
36
37
-List<monero.SubaddressAccountRow> getAllAccount() {
37
+ List<Wallet2SubaddressAccountRow> getAllAccount() {
38
// final size = monero.Wallet_numSubaddressAccounts(wptr!);
39
refreshAccounts();
40
- int size = monero.SubaddressAccount_getAll_size(subaddressAccount!);
40
+ int size = subaddressAccount!.getAll_size();
41
if (size == 0) {
42
- monero.Wallet_addSubaddressAccount(wptr!);
43
- monero.Wallet_status(wptr!);
42
+ currentWallet!.addSubaddressAccount();
43
+ currentWallet!.status();
44
return [];
45
}
46
return List.generate(size, (index) {
47
- return monero.SubaddressAccount_getAll_byIndex(subaddressAccount!, index: index);
47
+ return subaddressAccount!.getAll_byIndex(index);
48
});
49
}
50
51
-void addAccountSync({required String label}) {
52
- monero.Wallet_addSubaddressAccount(wptr!, label: label);
51
+void addAccount({required String label}) {
52
+ currentWallet!.addSubaddressAccount(label: label);
53
+ unawaited(store());
54
}
55
55
-void setLabelForAccountSync({required int accountIndex, required String label}) {
56
- monero.SubaddressAccount_setLabel(subaddressAccount!, accountIndex: accountIndex, label: label);
57
- MoneroAccountListBase.cachedAccounts[wptr!.address] = [];
56
+void setLabelForAccount({required int accountIndex, required String label}) {
57
+ subaddressAccount!.setLabel(accountIndex: accountIndex, label: label);
58
+ MoneroAccountListBase.cachedAccounts[currentWallet!.ffiAddress()] = [];
59
refreshAccounts();
59
-}
60
-
61
-void _addAccount(String label) => addAccountSync(label: label);
62
-
63
-void _setLabelForAccount(Map<String, dynamic> args) {
64
- final label = args['label'] as String;
65
- final accountIndex = args['accountIndex'] as int;
66
-
67
- setLabelForAccountSync(label: label, accountIndex: accountIndex);
68
-}
69
-
70
-Future<void> addAccount({required String label}) async {
71
- _addAccount(label);
60
unawaited(store());
61
}
74
-
75
-Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
76
- _setLabelForAccount({'accountIndex': accountIndex, 'label': label});
77
- unawaited(store());
78
-}
\ No newline at end of file
cw_monero/lib/api/coins_info.dart
+10
-9
@@ -3,17 +3,18 @@ import 'dart:isolate';
3
4
import 'package:cw_monero/api/account_list.dart';
5
import 'package:monero/monero.dart' as monero;
6
+import 'package:monero/src/wallet2.dart';
7
import 'package:mutex/mutex.dart';
8
8
-monero.Coins? coins = null;
9
+Wallet2Coins? coins = null;
10
final coinsMutex = Mutex();
11
12
Future<void> refreshCoins(int accountIndex) async {
13
if (coinsMutex.isLocked) {
14
return;
15
}
15
- coins = monero.Wallet_coins(wptr!);
16
- final coinsPtr = coins!.address;
16
+ coins = currentWallet!.coins();
17
+ final coinsPtr = coins!.ffiAddress();
18
await coinsMutex.acquire();
19
await Isolate.run(() => monero.Coins_refresh(Pointer.fromAddress(coinsPtr)));
20
coinsMutex.release();
@@ -21,14 +22,14 @@ Future<void> refreshCoins(int accountIndex) async {
22
23
Future<int> countOfCoins() async {
24
await coinsMutex.acquire();
24
- final count = monero.Coins_count(coins!);
25
+ final count = coins!.count();
26
coinsMutex.release();
27
return count;
28
}
29
29
-Future<monero.CoinsInfo> getCoin(int index) async {
30
+Future<Wallet2CoinsInfo> getCoin(int index) async {
31
await coinsMutex.acquire();
31
- final coin = monero.Coins_coin(coins!, index);
32
+ final coin = coins!.coin(index);
33
coinsMutex.release();
34
return coin;
35
}
@@ -37,7 +38,7 @@ Future<int?> getCoinByKeyImage(String keyImage) async {
38
final count = await countOfCoins();
39
for (int i = 0; i < count; i++) {
40
final coin = await getCoin(i);
40
- final coinAddress = monero.CoinsInfo_keyImage(coin);
41
+ final coinAddress = coin.keyImage;
42
if (keyImage == coinAddress) {
43
return i;
44
}
@@ -47,14 +48,14 @@ Future<int?> getCoinByKeyImage(String keyImage) async {
48
49
Future<void> freezeCoin(int index) async {
50
await coinsMutex.acquire();
50
- final coinsPtr = coins!.address;
51
+ final coinsPtr = coins!.ffiAddress();
52
await Isolate.run(() => monero.Coins_setFrozen(Pointer.fromAddress(coinsPtr), index: index));
53
coinsMutex.release();
54
}
55
56
Future<void> thawCoin(int index) async {
57
await coinsMutex.acquire();
57
- final coinsPtr = coins!.address;
58
+ final coinsPtr = coins!.ffiAddress();
59
await Isolate.run(() => monero.Coins_thaw(Pointer.fromAddress(coinsPtr), index: index));
60
coinsMutex.release();
61
}
cw_monero/lib/api/subaddress_list.dart
+20
-48
@@ -2,7 +2,8 @@
2
import 'package:cw_monero/api/account_list.dart';
3
import 'package:cw_monero/api/transaction_history.dart';
4
import 'package:cw_monero/api/wallet.dart';
5
-import 'package:monero/monero.dart' as monero;
5
+import 'package:monero/monero.dart';
6
+import 'package:monero/src/monero.dart';
7
8
bool isUpdating = false;
9
@@ -16,7 +17,7 @@ class SubaddressInfoMetadata {
17
SubaddressInfoMetadata? subaddress = null;
18
19
String getRawLabel({required int accountIndex, required int addressIndex}) {
19
- return monero.Wallet_getSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex);
20
+ return currentWallet!.getSubaddressLabel(accountIndex: accountIndex, addressIndex: addressIndex);
21
}
22
23
void refreshSubaddresses({required int accountIndex}) {
@@ -46,7 +47,7 @@ class Subaddress {
47
final int received;
48
final int txCount;
49
String get label {
49
- final localLabel = monero.Wallet_getSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex);
50
+ final localLabel = currentWallet!.getSubaddressLabel(accountIndex: accountIndex, addressIndex: addressIndex);
51
if (localLabel.startsWith("#$addressIndex")) return localLabel; // don't duplicate the ID if it was user-providen
52
return "#$addressIndex ${localLabel}".trim();
53
}
@@ -66,26 +67,26 @@ int lastTxCount = 0;
67
List<TinyTransactionDetails> ttDetails = [];
68
69
List<Subaddress> getAllSubaddresses() {
69
- txhistory = monero.Wallet_history(wptr!);
70
- final txCount = monero.TransactionHistory_count(txhistory!);
71
- if (lastTxCount != txCount && lastWptr != wptr!.address) {
70
+ txhistory = currentWallet!.history();
71
+ final txCount = txhistory!.count();
72
+ if (lastTxCount != txCount && lastWptr != currentWallet!.ffiAddress()) {
73
final List<TinyTransactionDetails> newttDetails = [];
74
lastTxCount = txCount;
74
- lastWptr = wptr!.address;
75
+ lastWptr = currentWallet!.ffiAddress();
76
for (var i = 0; i < txCount; i++) {
76
- final tx = monero.TransactionHistory_transaction(txhistory!, index: i);
77
- if (monero.TransactionInfo_direction(tx) == monero.TransactionInfo_Direction.Out) continue;
78
- final subaddrs = monero.TransactionInfo_subaddrIndex(tx).split(",");
79
- final account = monero.TransactionInfo_subaddrAccount(tx);
77
+ final tx = txhistory!.transaction(i);
78
+ if (tx.direction() == TransactionInfo_Direction.Out.index) continue;
79
+ final subaddrs = tx.subaddrIndex().split(",");
80
+ final account = tx.subaddrAccount();
81
newttDetails.add(TinyTransactionDetails(
82
address: List.generate(subaddrs.length, (index) => getAddress(accountIndex: account, addressIndex: int.tryParse(subaddrs[index])??0)),
82
- amount: monero.TransactionInfo_amount(tx),
83
+ amount: tx.amount(),
84
));
85
}
86
ttDetails.clear();
87
ttDetails.addAll(newttDetails);
88
}
88
- final size = monero.Wallet_numSubaddresses(wptr!, accountIndex: subaddress!.accountIndex);
89
+ final size = currentWallet!.numSubaddresses(accountIndex: subaddress!.accountIndex);
90
final list = List.generate(size, (index) {
91
final ttDetailsLocal = ttDetails.where((element) {
92
final address = getAddress(
@@ -119,46 +120,17 @@ List<Subaddress> getAllSubaddresses() {
120
}
121
122
int numSubaddresses(int subaccountIndex) {
122
- return monero.Wallet_numSubaddresses(wptr!, accountIndex: subaccountIndex);
123
-}
124
-
125
-void addSubaddressSync({required int accountIndex, required String label}) {
126
- monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex, label: label);
127
- refreshSubaddresses(accountIndex: accountIndex);
128
-}
129
-
130
-void setLabelForSubaddressSync(
131
- {required int accountIndex, required int addressIndex, required String label}) {
132
- monero.Wallet_setSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex, label: label);
133
-}
134
-
135
-void _addSubaddress(Map<String, dynamic> args) {
136
- final label = args['label'] as String;
137
- final accountIndex = args['accountIndex'] as int;
138
-
139
- addSubaddressSync(accountIndex: accountIndex, label: label);
140
-}
141
-
142
-void _setLabelForSubaddress(Map<String, dynamic> args) {
143
- final label = args['label'] as String;
144
- final accountIndex = args['accountIndex'] as int;
145
- final addressIndex = args['addressIndex'] as int;
146
-
147
- setLabelForSubaddressSync(
148
- accountIndex: accountIndex, addressIndex: addressIndex, label: label);
123
+ return currentWallet!.numSubaddresses(accountIndex: subaccountIndex);
124
}
125
126
Future<void> addSubaddress({required int accountIndex, required String label}) async {
152
- _addSubaddress({'accountIndex': accountIndex, 'label': label});
127
+ currentWallet!.addSubaddress(accountIndex: accountIndex, label: label);
128
+ refreshSubaddresses(accountIndex: accountIndex);
129
await store();
130
}
131
132
Future<void> setLabelForSubaddress(
157
- {required int accountIndex, required int addressIndex, required String label}) async {
158
- _setLabelForSubaddress({
159
- 'accountIndex': accountIndex,
160
- 'addressIndex': addressIndex,
161
- 'label': label
162
- });
133
+ {required int accountIndex, required int addressIndex, required String label}) async {
134
+ currentWallet!.setSubaddressLabel(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
135
await store();
164
-}
136
+}
\ No newline at end of file
cw_monero/lib/api/transaction_history.dart
+84
-109
@@ -9,36 +9,38 @@ import 'package:cw_monero/api/structs/pending_transaction.dart';
9
import 'package:cw_monero/api/wallet.dart';
10
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
11
import 'package:ffi/ffi.dart';
12
+import 'package:monero/src/monero.dart';
13
import 'package:monero/monero.dart' as monero;
14
+import 'package:monero/src/wallet2.dart';
15
import 'package:monero/src/generated_bindings_monero.g.dart' as monero_gen;
16
import 'package:mutex/mutex.dart';
17
18
19
Map<int, Map<String, String>> txKeys = {};
20
String getTxKey(String txId) {
19
- txKeys[wptr!.address] ??= {};
20
- if (txKeys[wptr!.address]![txId] != null) {
21
- return txKeys[wptr!.address]![txId]!;
21
+ txKeys[currentWallet!.ffiAddress()] ??= {};
22
+ if (txKeys[currentWallet!.ffiAddress()]![txId] != null) {
23
+ return txKeys[currentWallet!.ffiAddress()]![txId]!;
24
}
23
- final txKey = monero.Wallet_getTxKey(wptr!, txid: txId);
24
- final status = monero.Wallet_status(wptr!);
25
+ final txKey = currentWallet!.getTxKey(txid: txId);
26
+ final status = currentWallet!.status();
27
if (status != 0) {
26
- monero.Wallet_errorString(wptr!);
27
- txKeys[wptr!.address]![txId] = "";
28
+ currentWallet!.errorString();
29
+ txKeys[currentWallet!.ffiAddress()]![txId] = "";
30
return "";
31
}
30
- txKeys[wptr!.address]![txId] = txKey;
32
+ txKeys[currentWallet!.ffiAddress()]![txId] = txKey;
33
return txKey;
34
}
35
36
final txHistoryMutex = Mutex();
35
-monero.TransactionHistory? txhistory;
37
+Wallet2TransactionHistory? txhistory;
38
bool isRefreshingTx = false;
39
Future<void> refreshTransactions() async {
40
if (isRefreshingTx == true) return;
41
isRefreshingTx = true;
40
- txhistory ??= monero.Wallet_history(wptr!);
41
- final ptr = txhistory!.address;
42
+ txhistory ??= currentWallet!.history();
43
+ final ptr = txhistory!.ffiAddress();
44
await txHistoryMutex.acquire();
45
await Isolate.run(() {
46
monero.TransactionHistory_refresh(Pointer.fromAddress(ptr));
@@ -48,14 +50,14 @@ Future<void> refreshTransactions() async {
50
isRefreshingTx = false;
51
}
52
51
-int countOfTransactions() => monero.TransactionHistory_count(txhistory!);
53
+int countOfTransactions() => txhistory!.count();
54
55
Future<List<Transaction>> getAllTransactions() async {
56
List<Transaction> dummyTxs = [];
57
58
await txHistoryMutex.acquire();
57
- txhistory ??= monero.Wallet_history(wptr!);
58
- final startAddress = txhistory!.address * wptr!.address;
59
+ txhistory ??= currentWallet!.history();
60
+ final startAddress = txhistory!.ffiAddress() * currentWallet!.ffiAddress();
61
int size = countOfTransactions();
62
final list = <Transaction>[];
63
for (int index = 0; index < size; index++) {
@@ -63,21 +65,21 @@ Future<List<Transaction>> getAllTransactions() async {
65
// Give main thread a chance to do other things.
66
await Future.delayed(Duration.zero);
67
}
66
- if (txhistory!.address * wptr!.address != startAddress) {
68
+ if (txhistory!.ffiAddress() * currentWallet!.ffiAddress() != startAddress) {
69
printV("Loop broken because txhistory!.address * wptr!.address != startAddress");
70
break;
71
}
70
- final txInfo = monero.TransactionHistory_transaction(txhistory!, index: index);
71
- final txHash = monero.TransactionInfo_hash(txInfo);
72
- txCache[wptr!.address] ??= {};
73
- txCache[wptr!.address]![txHash] = Transaction(txInfo: txInfo);
74
- list.add(txCache[wptr!.address]![txHash]!);
72
+ final txInfo = txhistory!.transaction(index);
73
+ final txHash = txInfo.hash();
74
+ txCache[currentWallet!.ffiAddress()] ??= {};
75
+ txCache[currentWallet!.ffiAddress()]![txHash] = Transaction(txInfo: txInfo);
76
+ list.add(txCache[currentWallet!.ffiAddress()]![txHash]!);
77
}
78
txHistoryMutex.release();
77
- final accts = monero.Wallet_numSubaddressAccounts(wptr!);
79
+ final accts = currentWallet!.numSubaddressAccounts();
80
for (var i = 0; i < accts; i++) {
79
- final fullBalance = monero.Wallet_balance(wptr!, accountIndex: i);
80
- final availBalance = monero.Wallet_unlockedBalance(wptr!, accountIndex: i);
81
+ final fullBalance = currentWallet!.balance(accountIndex: i);
82
+ final availBalance = currentWallet!.unlockedBalance(accountIndex: i);
83
if (fullBalance > availBalance) {
84
if (list.where((element) => element.accountIndex == i && element.isConfirmed == false).isEmpty) {
85
dummyTxs.add(
@@ -95,7 +97,7 @@ Future<List<Transaction>> getAllTransactions() async {
97
isSpend: false,
98
hash: "pending",
99
key: "",
98
- txInfo: Pointer.fromAddress(0),
100
+ txInfo: DummyTransaction(),
101
)..timeStamp = DateTime.now()
102
);
103
}
@@ -105,16 +107,21 @@ Future<List<Transaction>> getAllTransactions() async {
107
return list;
108
}
109
110
+class DummyTransaction implements Wallet2TransactionInfo {
111
+ @override
112
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
113
+}
114
+
115
Map<int, Map<String, Transaction>> txCache = {};
116
Future<Transaction> getTransaction(String txId) async {
110
- if (txCache[wptr!.address] != null && txCache[wptr!.address]![txId] != null) {
111
- return txCache[wptr!.address]![txId]!;
117
+ if (txCache[currentWallet!.ffiAddress()] != null && txCache[currentWallet!.ffiAddress()]![txId] != null) {
118
+ return txCache[currentWallet!.ffiAddress()]![txId]!;
119
}
120
await txHistoryMutex.acquire();
114
- final tx = monero.TransactionHistory_transactionById(txhistory!, txid: txId);
121
+ final tx = txhistory!.transactionById(txId);
122
final txDart = Transaction(txInfo: tx);
116
- txCache[wptr!.address] ??= {};
117
- txCache[wptr!.address]![txId] = txDart;
123
+ txCache[currentWallet!.ffiAddress()] ??= {};
124
+ txCache[currentWallet!.ffiAddress()]![txId] = txDart;
125
txHistoryMutex.release();
126
return txDart;
127
}
@@ -127,9 +134,9 @@ Future<PendingTransactionDescription> createTransactionSync(
134
int accountIndex = 0,
135
List<String> preferredInputs = const []}) async {
136
130
- final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount);
137
+ final amt = amount == null ? 0 : currentWallet!.amountFromString(amount);
138
132
- final waddr = wptr!.address;
139
+ final waddr = currentWallet!.ffiAddress();
140
141
// force reconnection in case the os killed the connection?
142
// fixes failed to get block height error.
@@ -149,7 +156,7 @@ Future<PendingTransactionDescription> createTransactionSync(
156
final paymentIdAddr = paymentId_.address;
157
final preferredInputsAddr = preferredInputs_.address;
158
final spaddr = monero.defaultSeparator.address;
152
- final pendingTx = Pointer<Void>.fromAddress(await Isolate.run(() {
159
+ final pendingTxPtr = Pointer<Void>.fromAddress(await Isolate.run(() {
160
final tx = monero_gen.MoneroC(DynamicLibrary.open(monero.libPath)).MONERO_Wallet_createTransaction(
161
Pointer.fromAddress(waddr),
162
Pointer.fromAddress(addraddr).cast(),
@@ -163,15 +170,16 @@ Future<PendingTransactionDescription> createTransactionSync(
170
);
171
return tx.address;
172
}));
173
+ final Wallet2PendingTransaction pendingTx = MoneroPendingTransaction(pendingTxPtr);
174
calloc.free(address_);
175
calloc.free(paymentId_);
176
calloc.free(preferredInputs_);
177
final String? error = (() {
170
- final status = monero.PendingTransaction_status(pendingTx);
178
+ final status = pendingTx.status();
179
if (status == 0) {
180
return null;
181
}
174
- return monero.PendingTransaction_errorString(pendingTx);
182
+ return pendingTx.errorString();
183
})();
184
185
if (error != null) {
@@ -182,10 +190,10 @@ Future<PendingTransactionDescription> createTransactionSync(
190
throw CreationTransactionException(message: message);
191
}
192
185
- final rAmt = monero.PendingTransaction_amount(pendingTx);
186
- final rFee = monero.PendingTransaction_fee(pendingTx);
187
- final rHash = monero.PendingTransaction_txid(pendingTx, '');
188
- final rHex = monero.PendingTransaction_hex(pendingTx, '');
193
+ final rAmt = pendingTx.amount();
194
+ final rFee = pendingTx.fee();
195
+ final rHash = pendingTx.txid('');
196
+ final rHex = pendingTx.hex('');
197
final rTxKey = rHash;
198
199
return PendingTransactionDescription(
@@ -194,7 +202,7 @@ Future<PendingTransactionDescription> createTransactionSync(
202
hash: rHash,
203
hex: rHex,
204
txKey: rTxKey,
197
- pointerAddress: pendingTx.address,
205
+ pointerAddress: pendingTx.ffiAddress(),
206
);
207
}
208
@@ -206,9 +214,9 @@ Future<PendingTransactionDescription> createTransactionMultDest(
214
List<String> preferredInputs = const []}) async {
215
216
final dstAddrs = outputs.map((e) => e.address).toList();
209
- final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList();
217
+ final amounts = outputs.map((e) => currentWallet!.amountFromString(e.amount)).toList();
218
211
- final waddr = wptr!.address;
219
+ final waddr = currentWallet!.ffiAddress();
220
221
// force reconnection in case the os killed the connection
222
Isolate.run(() async {
@@ -227,49 +235,50 @@ Future<PendingTransactionDescription> createTransactionMultDest(
235
).address;
236
}));
237
230
- if (monero.PendingTransaction_status(txptr) != 0) {
231
- throw CreationTransactionException(message: monero.PendingTransaction_errorString(txptr));
238
+ final Wallet2PendingTransaction tx = MoneroPendingTransaction(txptr);
239
+
240
+ if (tx.status() != 0) {
241
+ throw CreationTransactionException(message: tx.errorString());
242
}
243
244
return PendingTransactionDescription(
235
- amount: monero.PendingTransaction_amount(txptr),
236
- fee: monero.PendingTransaction_fee(txptr),
237
- hash: monero.PendingTransaction_txid(txptr, ''),
238
- hex: monero.PendingTransaction_hex(txptr, ''),
239
- txKey: monero.PendingTransaction_txid(txptr, ''),
240
- pointerAddress: txptr.address,
245
+ amount: tx.amount(),
246
+ fee: tx.fee(),
247
+ hash: tx.txid(''),
248
+ hex: tx.hex(''),
249
+ txKey: tx.txid(''),
250
+ pointerAddress: tx.ffiAddress(),
251
);
252
}
253
254
String? commitTransactionFromPointerAddress({required int address, required bool useUR}) =>
245
- commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address), useUR: useUR);
255
+ commitTransaction(tx: MoneroPendingTransaction(Pointer.fromAddress(address)), useUR: useUR);
256
247
-String? commitTransaction({required monero.PendingTransaction transactionPointer, required bool useUR}) {
248
- final transactionPointerAddress = transactionPointer.address;
257
+String? commitTransaction({required Wallet2PendingTransaction tx, required bool useUR}) {
258
final txCommit = useUR
250
- ? monero.PendingTransaction_commitUR(transactionPointer, 120)
259
+ ? tx.commitUR(120)
260
: Isolate.run(() {
261
monero.PendingTransaction_commit(
253
- Pointer.fromAddress(transactionPointerAddress),
262
+ Pointer.fromAddress(tx.ffiAddress()),
263
filename: '',
264
overwrite: false,
265
);
266
});
267
268
String? error = (() {
260
- final status = monero.PendingTransaction_status(transactionPointer.cast());
269
+ final status = tx.status();
270
if (status == 0) {
271
return null;
272
}
264
- return monero.PendingTransaction_errorString(transactionPointer.cast());
273
+ return tx.errorString();
274
})();
275
if (error == null) {
276
error = (() {
268
- final status = monero.Wallet_status(wptr!);
277
+ final status = currentWallet!.status();
278
if (status == 0) {
279
return null;
280
}
272
- return monero.Wallet_errorString(wptr!);
281
+ return currentWallet!.errorString();
282
})();
283
284
}
@@ -283,43 +292,9 @@ String? commitTransaction({required monero.PendingTransaction transactionPointer
292
}
293
}
294
286
-Future<PendingTransactionDescription> _createTransactionSync(Map args) async {
287
- final address = args['address'] as String;
288
- final paymentId = args['paymentId'] as String;
289
- final amount = args['amount'] as String?;
290
- final priorityRaw = args['priorityRaw'] as int;
291
- final accountIndex = args['accountIndex'] as int;
292
- final preferredInputs = args['preferredInputs'] as List<String>;
293
-
294
- return createTransactionSync(
295
- address: address,
296
- paymentId: paymentId,
297
- amount: amount,
298
- priorityRaw: priorityRaw,
299
- accountIndex: accountIndex,
300
- preferredInputs: preferredInputs);
301
-}
302
-
303
-Future<PendingTransactionDescription> createTransaction(
304
- {required String address,
305
- required int priorityRaw,
306
- String? amount,
307
- String paymentId = '',
308
- int accountIndex = 0,
309
- List<String> preferredInputs = const []}) async =>
310
- _createTransactionSync({
311
- 'address': address,
312
- 'paymentId': paymentId,
313
- 'amount': amount,
314
- 'priorityRaw': priorityRaw,
315
- 'accountIndex': accountIndex,
316
- 'preferredInputs': preferredInputs
317
- });
318
-
295
class Transaction {
296
final String displayLabel;
321
- late final String subaddressLabel = monero.Wallet_getSubaddressLabel(
322
- wptr!,
297
+ late final String subaddressLabel = currentWallet!.getSubaddressLabel(
298
accountIndex: accountIndex,
299
addressIndex: addressIndex,
300
);
@@ -372,26 +347,26 @@ class Transaction {
347
// final SubAddress? subAddress;
348
// List<Transfer> transfers = [];
349
// final int txIndex;
375
- final monero.TransactionInfo txInfo;
350
+ final Wallet2TransactionInfo txInfo;
351
Transaction({
352
required this.txInfo,
378
- }) : displayLabel = monero.TransactionInfo_label(txInfo),
379
- hash = monero.TransactionInfo_hash(txInfo),
353
+ }) : displayLabel = txInfo.label(),
354
+ hash = txInfo.hash(),
355
timeStamp = DateTime.fromMillisecondsSinceEpoch(
381
- monero.TransactionInfo_timestamp(txInfo) * 1000,
356
+ txInfo.timestamp() * 1000,
357
),
383
- isSpend = monero.TransactionInfo_direction(txInfo) ==
384
- monero.TransactionInfo_Direction.Out,
385
- amount = monero.TransactionInfo_amount(txInfo),
386
- paymentId = monero.TransactionInfo_paymentId(txInfo),
387
- accountIndex = monero.TransactionInfo_subaddrAccount(txInfo),
388
- addressIndex = int.tryParse(monero.TransactionInfo_subaddrIndex(txInfo).split(", ")[0]) ?? 0,
389
- addressIndexList = monero.TransactionInfo_subaddrIndex(txInfo).split(", ").map((e) => int.tryParse(e) ?? 0).toList(),
390
- blockheight = monero.TransactionInfo_blockHeight(txInfo),
391
- confirmations = monero.TransactionInfo_confirmations(txInfo),
392
- fee = monero.TransactionInfo_fee(txInfo),
393
- description = monero.TransactionInfo_description(txInfo),
394
- key = getTxKey(monero.TransactionInfo_hash(txInfo));
358
+ isSpend = txInfo.direction() ==
359
+ monero.TransactionInfo_Direction.Out.index,
360
+ amount = txInfo.amount(),
361
+ paymentId = txInfo.paymentId(),
362
+ accountIndex = txInfo.subaddrAccount(),
363
+ addressIndex = int.tryParse(txInfo.subaddrIndex().split(", ")[0]) ?? 0,
364
+ addressIndexList = txInfo.subaddrIndex().split(", ").map((e) => int.tryParse(e) ?? 0).toList(),
365
+ blockheight = txInfo.blockHeight(),
366
+ confirmations = txInfo.confirmations(),
367
+ fee = txInfo.fee(),
368
+ description = txInfo.description(),
369
+ key = getTxKey(txInfo.hash());
370
371
Transaction.dummy({
372
required this.displayLabel,
cw_monero/lib/api/wallet.dart
+68
-89
@@ -5,8 +5,6 @@ import 'dart:isolate';
5
import 'package:cw_core/utils/print_verbose.dart';
6
import 'package:cw_monero/api/account_list.dart';
7
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
8
-import 'package:cw_monero/api/wallet_manager.dart';
9
-import 'package:flutter/foundation.dart';
8
import 'package:monero/monero.dart' as monero;
9
import 'package:mutex/mutex.dart';
10
import 'package:polyseed/polyseed.dart';
@@ -15,36 +13,37 @@ bool debugMonero = false;
13
14
int getSyncingHeight() {
15
// final height = monero.MONERO_cw_WalletListener_height(getWlptr());
18
- final h2 = monero.Wallet_blockChainHeight(wptr!);
16
+ if (currentWallet == null) return 0;
17
+ final h2 = currentWallet!.blockChainHeight();
18
// printV("height: $height / $h2");
19
return h2;
20
}
21
22
bool isNeededToRefresh() {
24
- final wlptr = getWlptr();
25
- if (wlptr == null) return false;
26
- final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(wlptr);
27
- monero.MONERO_cw_WalletListener_resetNeedToRefresh(wlptr);
23
+ final wl = getWlptr();
24
+ if (wl == null) return false;
25
+ final ret = wl.isNeedToRefresh();
26
+ wl.resetNeedToRefresh();
27
return ret;
28
}
29
30
bool isNewTransactionExist() {
31
final wlptr = getWlptr();
32
if (wlptr == null) return false;
34
- final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(wlptr);
35
- monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(wlptr);
33
+ final ret = wlptr.isNewTransactionExist();
34
+ wlptr.resetIsNewTransactionExist();
35
return ret;
36
}
37
39
-String getFilename() => monero.Wallet_filename(wptr!);
38
+String getFilename() => currentWallet!.filename();
39
40
String getSeed() {
41
// monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
42
final cakepolyseed =
44
- monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.seed");
43
+ currentWallet!.getCacheAttribute(key: "cakewallet.seed");
44
final cakepassphrase = getPassphrase();
45
47
- final weirdPolyseed = monero.Wallet_getPolyseed(wptr!, passphrase: cakepassphrase);
46
+ final weirdPolyseed = currentWallet!.getPolyseed(passphrase: cakepassphrase);
47
if (weirdPolyseed != "") return weirdPolyseed;
48
49
if (cakepolyseed != "") {
@@ -63,7 +62,7 @@ String getSeed() {
62
return cakepolyseed;
63
}
64
66
- final bip39 = monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.seed.bip39");
65
+ final bip39 = currentWallet!.getCacheAttribute(key: "cakewallet.seed.bip39");
66
67
if(bip39.isNotEmpty) return bip39;
68
@@ -85,29 +84,29 @@ String? getSeedLanguage(String? language) {
84
String getSeedLegacy(String? language) {
85
final cakepassphrase = getPassphrase();
86
language = getSeedLanguage(language);
88
- var legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
89
- if (monero.Wallet_status(wptr!) != 0) {
90
- if (monero.Wallet_errorString(wptr!).contains("seed_language")) {
91
- monero.Wallet_setSeedLanguage(wptr!, language: "English");
92
- legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
87
+ var legacy = currentWallet!.seed(seedOffset: cakepassphrase);
88
+ if (currentWallet!.status() != 0) {
89
+ if (currentWallet!.errorString().contains("seed_language")) {
90
+ currentWallet!.setSeedLanguage(language: "English");
91
+ legacy = currentWallet!.seed(seedOffset: cakepassphrase);
92
}
93
}
94
95
if (language != null) {
97
- monero.Wallet_setSeedLanguage(wptr!, language: language);
98
- final status = monero.Wallet_status(wptr!);
96
+ currentWallet!.setSeedLanguage(language: language);
97
+ final status = currentWallet!.status();
98
if (status != 0) {
100
- final err = monero.Wallet_errorString(wptr!);
99
+ final err = currentWallet!.errorString();
100
if (legacy.isNotEmpty) {
101
return "$err\n\n$legacy";
102
}
103
return err;
104
}
106
- legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
105
+ legacy = currentWallet!.seed(seedOffset: cakepassphrase);
106
}
107
109
- if (monero.Wallet_status(wptr!) != 0) {
110
- final err = monero.Wallet_errorString(wptr!);
108
+ if (currentWallet!.status() != 0) {
109
+ final err = currentWallet!.errorString();
110
if (legacy.isNotEmpty) {
111
return "$err\n\n$legacy";
112
}
@@ -117,7 +116,7 @@ String getSeedLegacy(String? language) {
116
}
117
118
String getPassphrase() {
120
- return monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.passphrase");
119
+ return currentWallet!.getCacheAttribute(key: "cakewallet.passphrase");
120
}
121
122
Map<int, Map<int, Map<int, String>>> addressCache = {};
@@ -125,31 +124,31 @@ Map<int, Map<int, Map<int, String>>> addressCache = {};
124
String getAddress({int accountIndex = 0, int addressIndex = 0}) {
125
// printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}");
126
// this could be a while loop, but I'm in favor of making it if to not cause freezes
128
- if (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) {
129
- if (monero.Wallet_numSubaddressAccounts(wptr!) < accountIndex) {
130
- monero.Wallet_addSubaddressAccount(wptr!);
127
+ if (currentWallet!.numSubaddresses(accountIndex: accountIndex)-1 < addressIndex) {
128
+ if (currentWallet!.numSubaddressAccounts() < accountIndex) {
129
+ currentWallet!.addSubaddressAccount();
130
} else {
132
- monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex);
131
+ currentWallet!.addSubaddress(accountIndex: accountIndex);
132
}
133
}
135
- addressCache[wptr!.address] ??= {};
136
- addressCache[wptr!.address]![accountIndex] ??= {};
137
- addressCache[wptr!.address]![accountIndex]![addressIndex] ??= monero.Wallet_address(wptr!,
134
+ addressCache[currentWallet!.ffiAddress()] ??= {};
135
+ addressCache[currentWallet!.ffiAddress()]![accountIndex] ??= {};
136
+ addressCache[currentWallet!.ffiAddress()]![accountIndex]![addressIndex] ??= currentWallet!.address(
137
accountIndex: accountIndex, addressIndex: addressIndex);
139
- return addressCache[wptr!.address]![accountIndex]![addressIndex]!;
138
+ return addressCache[currentWallet!.ffiAddress()]![accountIndex]![addressIndex]!;
139
}
140
141
int getFullBalance({int accountIndex = 0}) =>
143
- monero.Wallet_balance(wptr!, accountIndex: accountIndex);
142
+ currentWallet!.balance(accountIndex: accountIndex);
143
144
int getUnlockedBalance({int accountIndex = 0}) =>
146
- monero.Wallet_unlockedBalance(wptr!, accountIndex: accountIndex);
145
+ currentWallet!.unlockedBalance(accountIndex: accountIndex);
146
148
-int getCurrentHeight() => monero.Wallet_blockChainHeight(wptr!);
147
+int getCurrentHeight() => currentWallet!.blockChainHeight();
148
150
-int getNodeHeightSync() => monero.Wallet_daemonBlockChainHeight(wptr!);
149
+int getNodeHeightSync() => currentWallet!.daemonBlockChainHeight();
150
152
-bool isConnectedSync() => monero.Wallet_connected(wptr!) != 0;
151
+bool isConnectedSync() => currentWallet!.connected() != 0;
152
153
Future<bool> setupNodeSync(
154
{required String address,
@@ -168,7 +167,7 @@ Future<bool> setupNodeSync(
167
daemonPassword: $password ?? ''
168
}
169
''');
171
- final addr = wptr!.address;
170
+ final addr = currentWallet!.ffiAddress();
171
printV("init: start");
172
await Isolate.run(() {
173
monero.Wallet_init(Pointer.fromAddress(addr),
@@ -180,10 +179,10 @@ Future<bool> setupNodeSync(
179
});
180
printV("init: end");
181
183
- final status = monero.Wallet_status(wptr!);
182
+ final status = currentWallet!.status();
183
184
if (status != 0) {
186
- final error = monero.Wallet_errorString(wptr!);
185
+ final error = currentWallet!.errorString();
186
if (error != "no tx keys found for this txid") {
187
printV("error: $error");
188
throw SetupWalletException(message: error);
@@ -191,8 +190,8 @@ Future<bool> setupNodeSync(
190
}
191
192
if (true) {
194
- monero.Wallet_init3(
195
- wptr!, argv0: '',
193
+ currentWallet!.init3(
194
+ argv0: '',
195
defaultLogBaseName: 'moneroc',
196
console: true,
197
logPath: '',
@@ -203,19 +202,19 @@ Future<bool> setupNodeSync(
202
}
203
204
void startRefreshSync() {
206
- monero.Wallet_refreshAsync(wptr!);
207
- monero.Wallet_startRefresh(wptr!);
205
+ currentWallet!.refreshAsync();
206
+ currentWallet!.startRefresh();
207
}
208
209
210
void setRefreshFromBlockHeight({required int height}) {
212
- monero.Wallet_setRefreshFromBlockHeight(wptr!,
211
+ currentWallet!.setRefreshFromBlockHeight(
212
refresh_from_block_height: height);
213
}
214
215
void setRecoveringFromSeed({required bool isRecovery}) {
217
- monero.Wallet_setRecoveringFromSeed(wptr!, recoveringFromSeed: isRecovery);
218
- monero.Wallet_store(wptr!);
216
+ currentWallet!.setRecoveringFromSeed(recoveringFromSeed: isRecovery);
217
+ currentWallet!.store();
218
}
219
220
final storeMutex = Mutex();
@@ -224,18 +223,18 @@ final storeMutex = Mutex();
223
int lastStorePointer = 0;
224
int lastStoreHeight = 0;
225
void storeSync({bool force = false}) async {
227
- final addr = wptr!.address;
226
+ final addr = currentWallet!.ffiAddress();
227
final synchronized = await Isolate.run(() {
228
return monero.Wallet_synchronized(Pointer.fromAddress(addr));
229
});
231
- if (lastStorePointer == wptr!.address &&
232
- lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) &&
230
+ if (lastStorePointer == addr &&
231
+ lastStoreHeight + 5000 > currentWallet!.blockChainHeight() &&
232
!synchronized &&
233
!force) {
234
return;
235
}
237
- lastStorePointer = wptr!.address;
238
- lastStoreHeight = monero.Wallet_blockChainHeight(wptr!);
236
+ lastStorePointer = currentWallet!.ffiAddress();
237
+ lastStoreHeight = currentWallet!.blockChainHeight();
238
await storeMutex.acquire();
239
await Isolate.run(() {
240
monero.Wallet_store(Pointer.fromAddress(addr));
@@ -244,25 +243,25 @@ void storeSync({bool force = false}) async {
243
}
244
245
void setPasswordSync(String password) {
247
- monero.Wallet_setPassword(wptr!, password: password);
246
+ currentWallet!.setPassword(password: password);
247
249
- final status = monero.Wallet_status(wptr!);
248
+ final status = currentWallet!.status();
249
if (status != 0) {
251
- throw Exception(monero.Wallet_errorString(wptr!));
250
+ throw Exception(currentWallet!.errorString());
251
}
252
}
253
254
void closeCurrentWallet() {
256
- monero.Wallet_stop(wptr!);
255
+ currentWallet!.stop();
256
}
257
259
-String getSecretViewKey() => monero.Wallet_secretViewKey(wptr!);
258
+String getSecretViewKey() => currentWallet!.secretViewKey();
259
261
-String getPublicViewKey() => monero.Wallet_publicViewKey(wptr!);
260
+String getPublicViewKey() => currentWallet!.publicViewKey();
261
263
-String getSecretSpendKey() => monero.Wallet_secretSpendKey(wptr!);
262
+String getSecretSpendKey() => currentWallet!.secretSpendKey();
263
265
-String getPublicSpendKey() => monero.Wallet_publicSpendKey(wptr!);
264
+String getPublicSpendKey() => currentWallet!.publicSpendKey();
265
266
class SyncListener {
267
SyncListener(this.onNewBlock, this.onNewTransaction)
@@ -360,52 +359,32 @@ Future<bool> _setupNodeSync(Map<String, Object?> args) async {
359
socksProxyAddress: socksProxyAddress);
360
}
361
363
-bool _isConnected(Object _) => isConnectedSync();
364
-
365
-int _getNodeHeight(Object _) => getNodeHeightSync();
366
-
362
void startRefresh() => startRefreshSync();
363
369
-Future<void> setupNode(
370
- {required String address,
371
- String? login,
372
- String? password,
373
- bool useSSL = false,
374
- String? socksProxyAddress,
375
- bool isLightWallet = false}) async =>
376
- _setupNodeSync({
377
- 'address': address,
378
- 'login': login,
379
- 'password': password,
380
- 'useSSL': useSSL,
381
- 'isLightWallet': isLightWallet,
382
- 'socksProxyAddress': socksProxyAddress
383
- });
384
-
364
Future<void> store() async => _storeSync(0);
365
387
-Future<bool> isConnected() async => _isConnected(0);
366
+Future<bool> isConnected() async => isConnectedSync();
367
389
-Future<int> getNodeHeight() async => _getNodeHeight(0);
368
+Future<int> getNodeHeight() async => getNodeHeightSync();
369
391
-void rescanBlockchainAsync() => monero.Wallet_rescanBlockchainAsync(wptr!);
370
+void rescanBlockchainAsync() => currentWallet!.rescanBlockchainAsync();
371
372
String getSubaddressLabel(int accountIndex, int addressIndex) {
394
- return monero.Wallet_getSubaddressLabel(wptr!,
373
+ return currentWallet!.getSubaddressLabel(
374
accountIndex: accountIndex, addressIndex: addressIndex);
375
}
376
377
Future setTrustedDaemon(bool trusted) async =>
399
- monero.Wallet_setTrustedDaemon(wptr!, arg: trusted);
378
+ currentWallet!.setTrustedDaemon(arg: trusted);
379
401
-Future<bool> trustedDaemon() async => monero.Wallet_trustedDaemon(wptr!);
380
+Future<bool> trustedDaemon() async => currentWallet!.trustedDaemon();
381
382
String signMessage(String message, {String address = ""}) {
404
- return monero.Wallet_signMessage(wptr!, message: message, address: address);
383
+ return currentWallet!.signMessage(message: message, address: address);
384
}
385
386
bool verifyMessage(String message, String address, String signature) {
408
- return monero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature);
387
+ return currentWallet!.verifySignedMessage(message: message, address: address, signature: signature);
388
}
389
390
Map<String, List<int>> debugCallLength() => monero.debugCallLength;
cw_monero/lib/api/wallet_manager.dart
+103
-236
@@ -12,6 +12,8 @@ import 'package:cw_monero/api/transaction_history.dart';
12
import 'package:cw_monero/api/wallet.dart';
13
import 'package:cw_monero/ledger.dart';
14
import 'package:flutter/foundation.dart';
15
+import 'package:monero/src/monero.dart';
16
+import 'package:monero/src/wallet2.dart';
17
import 'package:monero/monero.dart' as monero;
18
19
class MoneroCException implements Exception {
@@ -24,9 +26,10 @@ class MoneroCException implements Exception {
26
}
27
28
void checkIfMoneroCIsFine() {
27
- final cppCsCpp = monero.MONERO_checksum_wallet2_api_c_cpp();
28
- final cppCsH = monero.MONERO_checksum_wallet2_api_c_h();
29
- final cppCsExp = monero.MONERO_checksum_wallet2_api_c_exp();
29
+ final checksum = MoneroWalletChecksum();
30
+ final cppCsCpp = checksum.checksum_wallet2_api_c_cpp();
31
+ final cppCsH = checksum.checksum_wallet2_api_c_h();
32
+ final cppCsExp = checksum.checksum_wallet2_api_c_exp();
33
34
final dartCsCpp = monero.wallet2_api_c_cpp_sha256;
35
final dartCsH = monero.wallet2_api_c_h_sha256;
@@ -44,36 +47,35 @@ void checkIfMoneroCIsFine() {
47
throw MoneroCException("monero_c and monero.dart wrapper export list mismatch.\nLogic errors can occur.\nRefusing to run in release mode.\ncpp: '$cppCsExp'\ndart: '$dartCsExp'");
48
}
49
}
47
-monero.WalletManager? _wmPtr;
48
-final monero.WalletManager wmPtr = Pointer.fromAddress((() {
50
+Wallet2WalletManager? _wmPtr;
51
+Wallet2WalletManager wmPtr = (() {
52
try {
53
// Problems with the wallet? Crashes? Lags? this will print all calls to xmr
54
// codebase, so it will be easier to debug what happens. At least easier
55
// than plugging gdb in. Especially on windows/android.
56
monero.printStarts = false;
57
if (kDebugMode && debugMonero) {
55
- monero.WalletManagerFactory_setLogLevel(4);
58
+ MoneroWalletManagerFactory().setLogLevel(4);
59
}
57
- _wmPtr ??= monero.WalletManagerFactory_getWalletManager();
60
+ _wmPtr ??= MoneroWalletManagerFactory().getWalletManager();
61
if (kDebugMode && debugMonero) {
59
- monero.WalletManagerFactory_setLogLevel(4);
62
+ MoneroWalletManagerFactory().setLogLevel(4);
63
}
64
printV("ptr: $_wmPtr");
65
} catch (e) {
66
printV(e);
67
rethrow;
68
}
66
- return _wmPtr!.address;
67
-})());
69
+ return _wmPtr!;
70
+})();
71
69
-void createWalletPointer() {
70
- final newWptr = monero.WalletManager_createWallet(wmPtr,
72
+Wallet2Wallet createWalletPointer() {
73
+ final newWptr = wmPtr.createWallet(
74
path: "", password: "", language: "", networkType: 0);
72
-
73
- wptr = newWptr;
75
+ return newWptr;
76
}
77
76
-void createWalletSync(
78
+void createWallet(
79
{required String path,
80
required String password,
81
required String language,
@@ -81,28 +83,25 @@ void createWalletSync(
83
int nettype = 0}) {
84
txhistory = null;
85
language = getSeedLanguage(language)!;
84
- final newWptr = monero.WalletManager_createWallet(wmPtr,
86
+ final newW = wmPtr.createWallet(
87
path: path, password: password, language: language, networkType: 0);
88
87
- int status = monero.Wallet_status(newWptr);
89
+ int status = newW.status();
90
if (status != 0) {
89
- throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
91
+ throw WalletCreationException(message: newW.errorString());
92
}
93
92
- setupBackgroundSync(password, newWptr);
94
+ setupBackgroundSync(password, newW);
95
94
- wptr = newWptr;
95
- monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
96
- monero.Wallet_store(wptr!, path: path);
97
- openedWalletsByPath[path] = wptr!;
96
+ currentWallet = newW;
97
+ currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: passphrase);
98
+ currentWallet!.store(path: path);
99
+ openedWalletsByPath[path] = currentWallet!;
100
_lastOpenedWallet = path;
99
-
100
- // is the line below needed?
101
- // setupNodeSync(address: "node.moneroworld.com:18089");
101
}
102
104
-bool isWalletExistSync({required String path}) {
105
- return monero.WalletManager_walletExists(wmPtr, path);
103
+bool isWalletExist({required String path}) {
104
+ return wmPtr.walletExists(path);
105
}
106
107
void restoreWalletFromSeedSync(
@@ -113,8 +112,7 @@ void restoreWalletFromSeedSync(
112
int nettype = 0,
113
int restoreHeight = 0}) {
114
txhistory = null;
116
- final newWptr = monero.WalletManager_recoveryWallet(
117
- wmPtr,
115
+ final newW = wmPtr.recoveryWallet(
116
path: path,
117
password: password,
118
mnemonic: seed,
@@ -123,10 +121,10 @@ void restoreWalletFromSeedSync(
121
networkType: 0,
122
);
123
126
- final status = monero.Wallet_status(newWptr);
124
+ final status = newW.status();
125
126
if (status != 0) {
129
- final error = monero.Wallet_errorString(newWptr);
127
+ final error = newW.errorString();
128
if (error.contains('word list failed verification')) {
129
throw WalletRestoreFromSeedException(
130
message: "Seed verification failed, please make sure you entered the correct seed with the correct words order",
@@ -134,20 +132,20 @@ void restoreWalletFromSeedSync(
132
}
133
throw WalletRestoreFromSeedException(message: error);
134
}
137
- wptr = newWptr;
135
+ currentWallet = newW;
136
137
setRefreshFromBlockHeight(height: restoreHeight);
140
- setupBackgroundSync(password, newWptr);
138
+ setupBackgroundSync(password, newW);
139
142
- monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
140
+ currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: passphrase);
141
144
- openedWalletsByPath[path] = wptr!;
142
+ openedWalletsByPath[path] = currentWallet!;
143
146
- monero.Wallet_store(wptr!);
144
+ currentWallet!.store(path: path);
145
_lastOpenedWallet = path;
146
}
147
150
-void restoreWalletFromKeysSync(
148
+void restoreWalletFromKeys(
149
{required String path,
150
required String password,
151
required String language,
@@ -157,8 +155,8 @@ void restoreWalletFromKeysSync(
155
int nettype = 0,
156
int restoreHeight = 0}) {
157
txhistory = null;
160
- var newWptr = (spendKey != "")
161
- ? monero.WalletManager_createDeterministicWalletFromSpendKey(wmPtr,
158
+ var newW = (spendKey != "")
159
+ ? wmPtr.createDeterministicWalletFromSpendKey(
160
path: path,
161
password: password,
162
language: language,
@@ -166,8 +164,7 @@ void restoreWalletFromKeysSync(
164
newWallet: true,
165
// TODO(mrcyjanek): safe to remove
166
restoreHeight: restoreHeight)
169
- : monero.WalletManager_createWalletFromKeys(
170
- wmPtr,
167
+ : wmPtr.createWalletFromKeys(
168
path: path,
169
password: password,
170
restoreHeight: restoreHeight,
@@ -177,22 +174,21 @@ void restoreWalletFromKeysSync(
174
nettype: 0,
175
);
176
180
- int status = monero.Wallet_status(newWptr);
177
+ int status = newW.status();
178
if (status != 0) {
179
throw WalletRestoreFromKeysException(
183
- message: monero.Wallet_errorString(newWptr));
180
+ message: newW.errorString());
181
}
182
183
// CW-712 - Try to restore deterministic wallet first, if the view key doesn't
184
// match the view key provided
185
if (spendKey != "") {
189
- final viewKeyRestored = monero.Wallet_secretViewKey(newWptr);
186
+ final viewKeyRestored = newW.secretViewKey();
187
if (viewKey != viewKeyRestored && viewKey != "") {
191
- monero.WalletManager_closeWallet(wmPtr, newWptr, false);
188
+ wmPtr.closeWallet(newW, false);
189
File(path).deleteSync();
190
File(path + ".keys").deleteSync();
194
- newWptr = monero.WalletManager_createWalletFromKeys(
195
- wmPtr,
191
+ newW = wmPtr.createWalletFromKeys(
192
path: path,
193
password: password,
194
restoreHeight: restoreHeight,
@@ -201,19 +197,19 @@ void restoreWalletFromKeysSync(
197
spendKeyString: spendKey,
198
nettype: 0,
199
);
204
- int status = monero.Wallet_status(newWptr);
200
+ int status = newW.status();
201
if (status != 0) {
202
throw WalletRestoreFromKeysException(
207
- message: monero.Wallet_errorString(newWptr));
203
+ message: newW.errorString());
204
}
205
210
- setupBackgroundSync(password, newWptr);
206
+ setupBackgroundSync(password, newW);
207
}
208
}
209
214
- wptr = newWptr;
210
+ currentWallet = newW;
211
216
- openedWalletsByPath[path] = wptr!;
212
+ openedWalletsByPath[path] = currentWallet!;
213
_lastOpenedWallet = path;
214
}
215
@@ -228,8 +224,7 @@ void restoreWalletFromPolyseedWithOffset(
224
int nettype = 0}) {
225
226
txhistory = null;
231
- final newWptr = monero.WalletManager_createWalletFromPolyseed(
232
- wmPtr,
227
+ final newW = wmPtr.createWalletFromPolyseed(
228
path: path,
229
password: password,
230
networkType: nettype,
@@ -240,24 +235,24 @@ void restoreWalletFromPolyseedWithOffset(
235
kdfRounds: 1,
236
);
237
243
- int status = monero.Wallet_status(newWptr);
238
+ int status = newW.status();
239
240
if (status != 0) {
246
- final err = monero.Wallet_errorString(newWptr);
241
+ final err = newW.errorString();
242
printV("err: $err");
243
throw WalletRestoreFromKeysException(message: err);
244
}
245
251
- wptr = newWptr;
246
+ currentWallet = newW;
247
253
- monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
254
- monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: seedOffset);
255
- monero.Wallet_store(wptr!);
248
+ currentWallet!.setCacheAttribute(key: "cakewallet.seed", value: seed);
249
+ currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: seedOffset);
250
+ currentWallet!.store(path: path);
251
257
- setupBackgroundSync(password, newWptr);
252
+ setupBackgroundSync(password, currentWallet!);
253
storeSync();
254
260
- openedWalletsByPath[path] = wptr!;
255
+ openedWalletsByPath[path] = currentWallet!;
256
}
257
258
@@ -282,8 +277,7 @@ void restoreWalletFromSpendKeySync(
277
// );
278
279
txhistory = null;
285
- final newWptr = monero.WalletManager_createDeterministicWalletFromSpendKey(
286
- wmPtr,
280
+ final newW = wmPtr.createDeterministicWalletFromSpendKey(
281
path: path,
282
password: password,
283
language: language,
@@ -292,23 +286,23 @@ void restoreWalletFromSpendKeySync(
286
restoreHeight: restoreHeight,
287
);
288
295
- int status = monero.Wallet_status(newWptr);
289
+ int status = newW.status();
290
291
if (status != 0) {
298
- final err = monero.Wallet_errorString(newWptr);
292
+ final err = newW.errorString();
293
printV("err: $err");
294
throw WalletRestoreFromKeysException(message: err);
295
}
296
303
- wptr = newWptr;
297
+ currentWallet = newW;
298
305
- monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
299
+ currentWallet!.setCacheAttribute(key: "cakewallet.seed", value: seed);
300
301
storeSync();
302
309
- setupBackgroundSync(password, newWptr);
303
+ setupBackgroundSync(password, currentWallet!);
304
311
- openedWalletsByPath[path] = wptr!;
305
+ openedWalletsByPath[path] = currentWallet!;
306
_lastOpenedWallet = path;
307
}
308
@@ -321,41 +315,42 @@ Future<void> restoreWalletFromHardwareWallet(
315
int nettype = 0,
316
int restoreHeight = 0}) async {
317
txhistory = null;
324
-
318
+ final wmPtr = MoneroWalletManagerFactory().getWalletManager().ffiAddress();
319
final newWptrAddr = await Isolate.run(() {
326
- return monero.WalletManager_createWalletFromDevice(wmPtr,
320
+ return monero.WalletManager_createWalletFromDevice(Pointer.fromAddress(wmPtr),
321
path: path,
322
password: password,
323
restoreHeight: restoreHeight,
324
deviceName: deviceName)
325
.address;
326
});
333
- final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
327
+ final newW = MoneroWallet(Pointer.fromAddress(newWptrAddr));
328
335
- final status = monero.Wallet_status(newWptr);
329
+ final status = newW.status();
330
331
if (status != 0) {
338
- final error = monero.Wallet_errorString(newWptr);
332
+ final error = newW.errorString();
333
throw WalletRestoreFromSeedException(message: error);
334
}
335
342
- wptr = newWptr;
336
+ currentWallet = newW;
337
+ currentWallet!.store(path: path);
338
_lastOpenedWallet = path;
344
- openedWalletsByPath[path] = wptr!;
339
+ openedWalletsByPath[path] = currentWallet!;
340
}
341
347
-Map<String, monero.wallet> openedWalletsByPath = {};
342
+Map<String, Wallet2Wallet> openedWalletsByPath = {};
343
344
Future<void> loadWallet(
345
{required String path, required String password, int nettype = 0}) async {
346
if (openedWalletsByPath[path] != null) {
347
txhistory = null;
353
- wptr = openedWalletsByPath[path]!;
348
+ currentWallet = openedWalletsByPath[path]!;
349
return;
350
}
356
- if (wptr == null || path != _lastOpenedWallet) {
357
- if (wptr != null) {
358
- final addr = wptr!.address;
351
+ if (currentWallet == null || path != _lastOpenedWallet) {
352
+ if (currentWallet != null) {
353
+ final addr = currentWallet!.ffiAddress();
354
Isolate.run(() {
355
monero.Wallet_store(Pointer.fromAddress(addr));
356
});
@@ -366,19 +361,24 @@ Future<void> loadWallet(
361
/// 0: Software Wallet
362
/// 1: Ledger
363
/// 2: Trezor
369
- late final deviceType;
364
+ var deviceType = 0;
365
366
if (Platform.isAndroid || Platform.isIOS) {
372
- deviceType = monero.WalletManager_queryWalletDevice(
373
- wmPtr,
367
+ deviceType = wmPtr.queryWalletDevice(
368
keysFileName: "$path.keys",
369
password: password,
370
kdfRounds: 1,
371
);
378
- final status = monero.WalletManager_errorString(wmPtr);
372
+ final status = wmPtr.errorString();
373
if (status != "") {
374
printV("loadWallet:"+status);
381
- throw WalletOpeningException(message: status);
375
+ // This is most likely closeWallet call leaking error. This is fine.
376
+ if (status.contains("failed to save file")) {
377
+ printV("loadWallet: error leaked: $status");
378
+ deviceType = 0;
379
+ } else {
380
+ throw WalletOpeningException(message: status);
381
+ }
382
}
383
} else {
384
deviceType = 0;
@@ -388,107 +388,47 @@ Future<void> loadWallet(
388
if (gLedger == null) {
389
throw Exception("Tried to open a ledger wallet with no ledger connected");
390
}
391
- final dummyWPtr = wptr ??
392
- monero.WalletManager_openWallet(wmPtr, path: '', password: '');
391
+ final dummyWPtr = (currentWallet ??
392
+ wmPtr.openWallet(path: '', password: ''));
393
enableLedgerExchange(dummyWPtr, gLedger!);
394
}
395
396
- final addr = wmPtr.address;
396
+ final addr = wmPtr.ffiAddress();
397
final newWptrAddr = await Isolate.run(() {
398
return monero.WalletManager_openWallet(Pointer.fromAddress(addr),
399
path: path, password: password)
400
.address;
401
});
402
403
- final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
403
+ final newW = MoneroWallet(Pointer.fromAddress(newWptrAddr));
404
405
- int status = monero.Wallet_status(newWptr);
405
+ int status = newW.status();
406
if (status != 0) {
407
- final err = monero.Wallet_errorString(newWptr);
407
+ final err = newW.errorString();
408
printV("loadWallet:"+err);
409
throw WalletOpeningException(message: err);
410
}
411
if (deviceType == 0) {
412
- setupBackgroundSync(password, newWptr);
412
+ setupBackgroundSync(password, newW);
413
}
414
415
- wptr = newWptr;
415
+ currentWallet = newW;
416
_lastOpenedWallet = path;
417
- openedWalletsByPath[path] = wptr!;
417
+ openedWalletsByPath[path] = currentWallet!;
418
}
419
}
420
421
-void setupBackgroundSync(String password, Pointer<Void>? wptrOverride) {
422
- if (isViewOnlyBySpendKey(wptrOverride)) {
421
+void setupBackgroundSync(String password, Wallet2Wallet wallet) {
422
+ if (isViewOnlyBySpendKey(wallet)) {
423
return;
424
}
425
- monero.Wallet_setupBackgroundSync(wptrOverride ?? wptr!, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
426
- if (monero.Wallet_status(wptrOverride ?? wptr!) != 0) {
425
+ wallet.setupBackgroundSync(backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
426
+ if (wallet.status() != 0) {
427
// We simply ignore the error.
428
- printV("setupBackgroundSync: ${monero.Wallet_errorString(wptrOverride ?? wptr!)}");
428
+ printV("setupBackgroundSync: ${wallet.errorString()}");
429
}
430
}
431
432
-void _createWallet(Map<String, dynamic> args) {
433
- final path = args['path'] as String;
434
- final password = args['password'] as String;
435
- final language = args['language'] as String;
436
- final passphrase = args['passphrase'] as String;
437
-
438
- createWalletSync(path: path, password: password, language: language, passphrase: passphrase);
439
-}
440
-
441
-void _restoreFromSeed(Map<String, dynamic> args) {
442
- final path = args['path'] as String;
443
- final password = args['password'] as String;
444
- final passphrase = args['passphrase'] as String;
445
- final seed = args['seed'] as String;
446
- final restoreHeight = args['restoreHeight'] as int;
447
-
448
- return restoreWalletFromSeedSync(
449
- path: path, password: password, passphrase: passphrase, seed: seed, restoreHeight: restoreHeight);
450
-}
451
-
452
-void _restoreFromKeys(Map<String, dynamic> args) {
453
- final path = args['path'] as String;
454
- final password = args['password'] as String;
455
- final language = args['language'] as String;
456
- final restoreHeight = args['restoreHeight'] as int;
457
- final address = args['address'] as String;
458
- final viewKey = args['viewKey'] as String;
459
- final spendKey = args['spendKey'] as String;
460
-
461
- restoreWalletFromKeysSync(
462
- path: path,
463
- password: password,
464
- language: language,
465
- restoreHeight: restoreHeight,
466
- address: address,
467
- viewKey: viewKey,
468
- spendKey: spendKey);
469
-}
470
-
471
-void _restoreFromSpendKey(Map<String, dynamic> args) {
472
- final path = args['path'] as String;
473
- final password = args['password'] as String;
474
- final seed = args['seed'] as String;
475
- final language = args['language'] as String;
476
- final spendKey = args['spendKey'] as String;
477
- final restoreHeight = args['restoreHeight'] as int;
478
-
479
- restoreWalletFromSpendKeySync(
480
- path: path,
481
- password: password,
482
- seed: seed,
483
- language: language,
484
- restoreHeight: restoreHeight,
485
- spendKey: spendKey);
486
-}
487
-
488
-Future<void> _openWallet(Map<String, String> args) async => loadWallet(
489
- path: args['path'] as String, password: args['password'] as String);
490
-
491
-bool _isWalletExist(String path) => isWalletExistSync(path: path);
432
433
Future<void> openWallet(
434
{required String path,
@@ -496,77 +436,4 @@ Future<void> openWallet(
436
int nettype = 0}) async =>
437
loadWallet(path: path, password: password, nettype: nettype);
438
499
-Future<void> openWalletAsync(Map<String, String> args) async =>
500
- _openWallet(args);
501
-
502
-Future<void> createWallet(
503
- {required String path,
504
- required String password,
505
- required String language,
506
- required String passphrase,
507
- int nettype = 0}) async =>
508
- _createWallet({
509
- 'path': path,
510
- 'password': password,
511
- 'language': language,
512
- 'passphrase': passphrase,
513
- 'nettype': nettype
514
- });
515
-
516
-void restoreFromSeed(
517
- {required String path,
518
- required String password,
519
- required String passphrase,
520
- required String seed,
521
- int nettype = 0,
522
- int restoreHeight = 0}) =>
523
- _restoreFromSeed({
524
- 'path': path,
525
- 'password': password,
526
- 'passphrase': passphrase,
527
- 'seed': seed,
528
- 'nettype': nettype,
529
- 'restoreHeight': restoreHeight
530
- });
531
-
532
-Future<void> restoreFromKeys(
533
- {required String path,
534
- required String password,
535
- required String language,
536
- required String address,
537
- required String viewKey,
538
- required String spendKey,
539
- int nettype = 0,
540
- int restoreHeight = 0}) async =>
541
- _restoreFromKeys({
542
- 'path': path,
543
- 'password': password,
544
- 'language': language,
545
- 'address': address,
546
- 'viewKey': viewKey,
547
- 'spendKey': spendKey,
548
- 'nettype': nettype,
549
- 'restoreHeight': restoreHeight
550
- });
551
-
552
-Future<void> restoreFromSpendKey(
553
- {required String path,
554
- required String password,
555
- required String seed,
556
- required String language,
557
- required String spendKey,
558
- int nettype = 0,
559
- int restoreHeight = 0}) async =>
560
- _restoreFromSpendKey({
561
- 'path': path,
562
- 'password': password,
563
- 'seed': seed,
564
- 'language': language,
565
- 'spendKey': spendKey,
566
- 'nettype': nettype,
567
- 'restoreHeight': restoreHeight
568
- });
569
-
570
-bool isWalletExist({required String path}) => _isWalletExist(path);
571
-
572
-bool isViewOnlyBySpendKey(Pointer<Void>? wptrOverride) => int.tryParse(monero.Wallet_secretSpendKey(wptrOverride ?? wptr!)) == 0;
439
+bool isViewOnlyBySpendKey(Wallet2Wallet? wallet) => int.tryParse((wallet??currentWallet!).secretSpendKey()) == 0;
cw_monero/lib/ledger.dart
+8
-8
@@ -7,26 +7,26 @@ import 'package:cw_core/utils/print_verbose.dart';
7
import 'package:ffi/ffi.dart';
8
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
9
import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart';
10
-import 'package:monero/monero.dart' as monero;
10
+import 'package:monero/src/wallet2.dart';
11
12
LedgerConnection? gLedger;
13
14
Timer? _ledgerExchangeTimer;
15
Timer? _ledgerKeepAlive;
16
17
-void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) {
17
+void enableLedgerExchange(Wallet2Wallet wallet, LedgerConnection connection) {
18
_ledgerExchangeTimer?.cancel();
19
_ledgerExchangeTimer = Timer.periodic(Duration(milliseconds: 1), (_) async {
20
- final ledgerRequestLength = monero.Wallet_getSendToDeviceLength(ptr);
21
- final ledgerRequest = monero.Wallet_getSendToDevice(ptr)
20
+ final ledgerRequestLength = wallet.getSendToDeviceLength();
21
+ final ledgerRequest = wallet.getSendToDevice()
22
.cast<Uint8>()
23
.asTypedList(ledgerRequestLength);
24
if (ledgerRequestLength > 0) {
25
_ledgerKeepAlive?.cancel();
26
27
final Pointer<Uint8> emptyPointer = malloc<Uint8>(0);
28
- monero.Wallet_setDeviceSendData(
29
- ptr, emptyPointer.cast<UnsignedChar>(), 0);
28
+ wallet.setDeviceSendData(
29
+ emptyPointer.cast<UnsignedChar>(), 0);
30
malloc.free(emptyPointer);
31
32
_logLedgerCommand(ledgerRequest, false);
@@ -45,8 +45,8 @@ void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) {
45
result.asTypedList(response.length)[i] = response[i];
46
}
47
48
- monero.Wallet_setDeviceReceivedData(
49
- ptr, result.cast<UnsignedChar>(), response.length);
48
+ wallet.setDeviceReceivedData(
49
+ result.cast<UnsignedChar>(), response.length);
50
malloc.free(result);
51
keepAlive(connection);
52
}
cw_monero/lib/monero_account_list.dart
+14
-14
@@ -4,7 +4,7 @@ import 'package:cw_monero/api/wallet_manager.dart';
4
import 'package:mobx/mobx.dart';
5
import 'package:cw_core/account.dart';
6
import 'package:cw_monero/api/account_list.dart' as account_list;
7
-import 'package:monero/monero.dart' as monero;
7
+import 'package:monero/src/monero.dart';
8
9
part 'monero_account_list.g.dart';
10
@@ -50,32 +50,32 @@ abstract class MoneroAccountListBase with Store {
50
List<Account> getAll() {
51
final allAccounts = account_list.getAllAccount();
52
final currentCount = allAccounts.length;
53
- cachedAccounts[account_list.wptr!.address] ??= [];
53
+ cachedAccounts[account_list.currentWallet!.ffiAddress()] ??= [];
54
55
- if (cachedAccounts[account_list.wptr!.address]!.length == currentCount) {
56
- return cachedAccounts[account_list.wptr!.address]!;
55
+ if (cachedAccounts[account_list.currentWallet!.ffiAddress()]!.length == currentCount) {
56
+ return cachedAccounts[account_list.currentWallet!.ffiAddress()]!;
57
}
58
59
- cachedAccounts[account_list.wptr!.address] = allAccounts.map((accountRow) {
60
- final balance = monero.SubaddressAccountRow_getUnlockedBalance(accountRow);
59
+ cachedAccounts[account_list.currentWallet!.ffiAddress()] = allAccounts.map((accountRow) {
60
+ final balance = accountRow.getUnlockedBalance();
61
62
return Account(
63
- id: monero.SubaddressAccountRow_getRowId(accountRow),
64
- label: monero.SubaddressAccountRow_getLabel(accountRow),
65
- balance: moneroAmountToString(amount: monero.Wallet_amountFromString(balance)),
63
+ id: accountRow.getRowId(),
64
+ label: accountRow.getLabel(),
65
+ balance: moneroAmountToString(amount: account_list.currentWallet!.amountFromString(balance)),
66
);
67
}).toList();
68
69
- return cachedAccounts[account_list.wptr!.address]!;
69
+ return cachedAccounts[account_list.currentWallet!.ffiAddress()]!;
70
}
71
72
- Future<void> addAccount({required String label}) async {
73
- await account_list.addAccount(label: label);
72
+ void addAccount({required String label}) {
73
+ account_list.addAccount(label: label);
74
update();
75
}
76
77
- Future<void> setLabelAccount({required int accountIndex, required String label}) async {
78
- await account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
77
+ void setLabelAccount({required int accountIndex, required String label}) {
78
+ account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
79
update();
80
}
81
cw_monero/lib/monero_unspent.dart
+1
-1
@@ -1,7 +1,7 @@
1
import 'package:cw_core/unspent_transaction_output.dart';
2
import 'package:cw_core/utils/print_verbose.dart';
3
import 'package:cw_monero/api/coins_info.dart';
4
-import 'package:monero/monero.dart' as monero;
4
+import 'package:monero/src/monero.dart';
5
6
class MoneroUnspent extends Unspent {
7
static Future<MoneroUnspent> fromUnspent(String address, String hash, String keyImage, int value, bool isFrozen, bool isUnlocked) async {
cw_monero/lib/monero_wallet.dart
+96
-75
@@ -39,6 +39,7 @@ import 'package:flutter/foundation.dart';
39
import 'package:hive/hive.dart';
40
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
41
import 'package:mobx/mobx.dart';
42
+import 'package:monero/src/monero.dart' as m;
43
import 'package:monero/monero.dart' as monero;
44
45
part 'monero_wallet.g.dart';
@@ -84,7 +85,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
85
monero_wallet.getUnlockedBalance(accountIndex: account.id))
86
});
87
_updateSubAddress(isEnabledAutoGenerateSubaddress, account: account);
87
- _askForUpdateTransactionHistory();
88
+ unawaited(updateTransactions());
89
});
90
91
reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
@@ -139,7 +140,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
140
passphrase: monero_wallet.getPassphrase());
141
142
int? get restoreHeight =>
142
- transactionHistory.transactions.values.firstOrNull?.height ?? monero.Wallet_getRefreshFromBlockHeight(wptr!);
143
+ transactionHistory.transactions.values.firstOrNull?.height ?? currentWallet?.getRefreshFromBlockHeight();
144
145
monero_wallet.SyncListener? _listener;
146
ReactionDisposer? _onAccountChangeReaction;
@@ -169,7 +170,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
170
if (monero_wallet.getCurrentHeight() <= 1) {
171
monero_wallet.setRefreshFromBlockHeight(
172
height: walletInfo.restoreHeight);
172
- setupBackgroundSync(password, wptr!);
173
+ setupBackgroundSync(password, currentWallet!);
174
}
175
}
176
@@ -189,14 +190,23 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
190
final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
191
if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) {
192
printV("closing wallet");
192
- final wmaddr = wmPtr.address;
193
- final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address;
194
- await Isolate.run(() {
195
- monero.WalletManager_closeWallet(
196
- Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
197
- });
193
+ final wmaddr = wmPtr.ffiAddress();
194
+ final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.ffiAddress();
195
openedWalletsByPath.remove("$currentWalletDirPath/$name");
199
- wptr = null;
196
+ if (Platform.isWindows) {
197
+ await Isolate.run(() {
198
+ monero.WalletManager_closeWallet(
199
+ Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
200
+ monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
201
+ });
202
+ } else {
203
+ unawaited(Isolate.run(() {
204
+ monero.WalletManager_closeWallet(
205
+ Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
206
+ monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
207
+ }));
208
+ }
209
+ currentWallet = null;
210
printV("wallet closed");
211
}
212
}
@@ -211,7 +221,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
221
Future<void> connectToNode({required Node node}) async {
222
try {
223
syncStatus = ConnectingSyncStatus();
214
- await monero_wallet.setupNode(
224
+ await monero_wallet.setupNodeSync(
225
address: node.uri.toString(),
226
login: node.login,
227
password: node.password,
@@ -237,10 +247,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
247
isBackgroundSyncRunning = true;
248
await save();
249
240
- monero.Wallet_startBackgroundSync(wptr!);
241
- final status = monero.Wallet_status(wptr!);
250
+ currentWallet!.startBackgroundSync();
251
+ final status = currentWallet!.status();
252
if (status != 0) {
243
- final err = monero.Wallet_errorString(wptr!);
253
+ final err = currentWallet!.errorString();
254
isBackgroundSyncRunning = false;
255
printV("startBackgroundSync: $err");
256
}
@@ -256,9 +266,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
266
Future<void> stopSync() async {
267
if (isBackgroundSyncRunning) {
268
printV("Stopping background sync");
259
- monero.Wallet_store(wptr!);
260
- monero.Wallet_stopBackgroundSync(wptr!, '');
261
- monero_wallet.store();
269
+ currentWallet!.store();
270
+ currentWallet!.stopBackgroundSync('');
271
+ currentWallet!.store();
272
isBackgroundSyncRunning = false;
273
}
274
await save();
@@ -269,9 +279,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
279
Future<void> stopBackgroundSync(String password) async {
280
if (isBackgroundSyncRunning) {
281
printV("Stopping background sync");
272
- monero.Wallet_store(wptr!);
273
- monero.Wallet_stopBackgroundSync(wptr!, password);
274
- monero.Wallet_store(wptr!);
282
+ currentWallet!.store();
283
+ currentWallet!.stopBackgroundSync(password);
284
+ currentWallet!.store();
285
isBackgroundSyncRunning = false;
286
}
287
}
@@ -308,44 +318,44 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
318
}
319
320
Future<bool> submitTransactionUR(String ur) async {
311
- final retStatus = monero.Wallet_submitTransactionUR(wptr!, ur);
312
- final status = monero.Wallet_status(wptr!);
321
+ final retStatus = currentWallet!.submitTransactionUR(ur);
322
+ final status = currentWallet!.status();
323
if (status != 0) {
314
- final err = monero.Wallet_errorString(wptr!);
324
+ final err = currentWallet!.errorString();
325
throw MoneroTransactionCreationException("unable to broadcast signed transaction: $err");
326
}
327
return retStatus;
328
}
329
330
bool importKeyImagesUR(String ur) {
321
- final retStatus = monero.Wallet_importKeyImagesUR(wptr!, ur);
322
- final status = monero.Wallet_status(wptr!);
331
+ final retStatus = currentWallet!.importKeyImagesUR(ur);
332
+ final status = currentWallet!.status();
333
if (status != 0) {
324
- final err = monero.Wallet_errorString(wptr!);
334
+ final err = currentWallet!.errorString();
335
throw Exception("unable to import key images: $err");
336
}
337
return retStatus;
338
}
339
340
String exportOutputsUR(bool all) {
331
- final str = monero.Wallet_exportOutputsUR(wptr!, all: all);
332
- final status = monero.Wallet_status(wptr!);
341
+ final str = currentWallet!.exportOutputsUR(all: all);
342
+ final status = currentWallet!.status();
343
if (status != 0) {
334
- final err = monero.Wallet_errorString(wptr!);
344
+ final err = currentWallet!.errorString();
345
throw MoneroTransactionCreationException("unable to export UR: $err");
346
}
347
return str;
348
}
349
350
bool needExportOutputs(int amount) {
341
- if (int.tryParse(monero.Wallet_secretSpendKey(wptr!)) != 0) {
351
+ if (int.tryParse(currentWallet!.secretSpendKey()) != 0) {
352
return false;
353
}
354
// viewOnlyBalance - balance that we can spend
355
// TODO(mrcyjanek): remove hasUnknownKeyImages when we cleanup coin control
346
- return (monero.Wallet_viewOnlyBalance(wptr!,
356
+ return (currentWallet!.viewOnlyBalance(
357
accountIndex: walletAddresses.account!.id) < amount) ||
348
- monero.Wallet_hasUnknownKeyImages(wptr!);
358
+ currentWallet!.hasUnknownKeyImages();
359
}
360
361
@override
@@ -425,12 +435,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
435
if (inputs.isEmpty) MoneroTransactionCreationException(
436
'No inputs selected');
437
pendingTransactionDescription =
428
- await transaction_history.createTransaction(
438
+ await transaction_history.createTransactionSync(
439
address: address!,
440
amount: amount,
441
priorityRaw: _credentials.priority.serialize(),
442
accountIndex: walletAddresses.account!.id,
433
- preferredInputs: inputs);
443
+ preferredInputs: inputs,
444
+ paymentId: '');
445
}
446
447
// final status = monero.PendingTransaction_status(pendingTransactionDescription);
@@ -485,14 +496,25 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
496
final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
497
if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) {
498
// NOTE: this is realistically only required on windows.
499
+ // That's why we await it only on that platform - other platforms actually understand
500
+ // the concept of a file properly...
501
printV("closing wallet");
489
- final wmaddr = wmPtr.address;
490
- final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address;
491
- await Isolate.run(() {
492
- monero.WalletManager_closeWallet(
493
- Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
494
- });
502
+ final wmaddr = wmPtr.ffiAddress();
503
+ final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.ffiAddress();
504
openedWalletsByPath.remove("$currentWalletDirPath/$name");
505
+ if (Platform.isWindows) {
506
+ await Isolate.run(() {
507
+ monero.WalletManager_closeWallet(
508
+ Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
509
+ monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
510
+ });
511
+ } else {
512
+ unawaited(Isolate.run(() {
513
+ monero.WalletManager_closeWallet(
514
+ Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
515
+ monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
516
+ }));
517
+ }
518
printV("wallet closed");
519
}
520
try {
@@ -501,32 +523,33 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
523
Directory(await pathForWalletDir(name: name, type: type));
524
final newWalletDirPath =
525
await pathForWalletDir(name: newWalletName, type: type);
504
- await currentWalletDir.rename(newWalletDirPath);
505
-
506
- // -- use new waller folder to rename files with old names still --
507
- final renamedWalletPath = newWalletDirPath + '/$name';
508
-
509
- final currentCacheFile = File(renamedWalletPath);
510
- final currentKeysFile = File('$renamedWalletPath.keys');
511
- final currentAddressListFile = File('$renamedWalletPath.address.txt');
512
- final backgroundSyncFile = File('$renamedWalletPath.background');
513
-
514
- final newWalletPath =
515
- await pathForWallet(name: newWalletName, type: type);
526
+
527
+ // Create new directory if it doesn't exist
528
+ await Directory(newWalletDirPath).create(recursive: true);
529
+
530
+ // -- use new waller folder to copy files with old names still --
531
+ final currentWalletPath = currentWalletDir.path + '/$name';
532
+
533
+ final currentCacheFile = File(currentWalletPath);
534
+ final currentKeysFile = File('$currentWalletPath.keys');
535
+ final currentAddressListFile = File('$currentWalletPath.address.txt');
536
+ final backgroundSyncFile = File('$currentWalletPath.background');
537
538
if (currentCacheFile.existsSync()) {
518
- await currentCacheFile.rename(newWalletPath);
539
+ await currentCacheFile.copy("${newWalletDirPath}/$newWalletName");
540
}
541
if (currentKeysFile.existsSync()) {
521
- await currentKeysFile.rename('$newWalletPath.keys');
542
+ await currentKeysFile.copy("${newWalletDirPath}/$newWalletName.keys");
543
}
544
if (currentAddressListFile.existsSync()) {
524
- await currentAddressListFile.rename('$newWalletPath.address.txt');
545
+ await currentAddressListFile.copy("${newWalletDirPath}/$newWalletName.address.txt");
546
}
547
if (backgroundSyncFile.existsSync()) {
527
- await backgroundSyncFile.rename('$newWalletPath.background');
548
+ await backgroundSyncFile.copy("${newWalletDirPath}/$newWalletName.background");
549
}
550
551
+ await currentWalletDir.delete(recursive: true);
552
+
553
await backupWalletFiles(newWalletName);
554
} catch (e) {
555
final currentWalletPath = await pathForWallet(name: name, type: type);
@@ -572,12 +595,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
595
walletInfo.restoreHeight = height;
596
walletInfo.isRecovery = true;
597
monero_wallet.setRefreshFromBlockHeight(height: height);
575
- setupBackgroundSync(password, wptr!);
598
+ setupBackgroundSync(password, currentWallet!);
599
monero_wallet.rescanBlockchainAsync();
600
await startSync();
601
_askForUpdateBalance();
602
walletAddresses.accountList.update();
580
- await _askForUpdateTransactionHistory();
603
+ await updateTransactions();
604
await save();
605
await walletInfo.save();
606
}
@@ -591,15 +614,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
614
final coinCount = await countOfCoins();
615
for (var i = 0; i < coinCount; i++) {
616
final coin = await getCoin(i);
594
- final coinSpent = monero.CoinsInfo_spent(coin);
595
- if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) {
617
+ final coinSpent = coin.spent();
618
+ if (coinSpent == false && coin.subaddrAccount() == walletAddresses.account!.id) {
619
final unspent = await MoneroUnspent.fromUnspent(
597
- monero.CoinsInfo_address(coin),
598
- monero.CoinsInfo_hash(coin),
599
- monero.CoinsInfo_keyImage(coin),
600
- monero.CoinsInfo_amount(coin),
601
- monero.CoinsInfo_frozen(coin),
602
- monero.CoinsInfo_unlocked(coin),
620
+ coin.address(),
621
+ coin.hash(),
622
+ coin.keyImage(),
623
+ coin.amount(),
624
+ coin.frozen(),
625
+ coin.unlocked(),
626
);
627
// TODO: double-check the logic here
628
if (unspent.hash.isNotEmpty) {
@@ -704,6 +727,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
727
acc[tx.id] = tx;
728
return acc;
729
});
730
+ // This is needed to update the transaction history when new transaction is made.
731
+ unawaited(updateTransactions());
732
return resp;
733
}
734
@@ -792,7 +817,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
817
818
monero_wallet.setRecoveringFromSeed(isRecovery: true);
819
monero_wallet.setRefreshFromBlockHeight(height: height);
795
- setupBackgroundSync(password, wptr!);
820
+ setupBackgroundSync(password, currentWallet!);
821
}
822
823
int _getHeightDistance(DateTime date) {
@@ -831,9 +856,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
856
}
857
}
858
834
- Future<void> _askForUpdateTransactionHistory() async =>
835
- await updateTransactions();
836
-
859
int _getUnlockedBalance() => monero_wallet.getUnlockedBalance(
860
accountIndex: walletAddresses.account!.id);
861
@@ -852,13 +874,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
874
printV("onNewBlock: $height, $blocksLeft, $ptc");
875
try {
876
if (walletInfo.isRecovery) {
855
- await _askForUpdateTransactionHistory();
877
+ await updateTransactions();
878
_askForUpdateBalance();
879
walletAddresses.accountList.update();
880
}
881
882
if (blocksLeft < 100) {
861
- await _askForUpdateTransactionHistory();
883
+ await updateTransactions();
884
_askForUpdateBalance();
885
walletAddresses.accountList.update();
886
syncStatus = SyncedSyncStatus();
@@ -881,7 +903,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
903
904
void _onNewTransaction() async {
905
try {
884
- await _askForUpdateTransactionHistory();
906
+ await updateTransactions();
907
_askForUpdateBalance();
908
await Future<void>.delayed(Duration(seconds: 1));
909
} catch (e) {
@@ -917,8 +939,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
939
}
940
941
void setLedgerConnection(LedgerConnection connection) {
920
- final dummyWPtr = wptr ??
921
- monero.WalletManager_openWallet(wmPtr, path: '', password: '');
942
+ final dummyWPtr = createWalletPointer();
943
enableLedgerExchange(dummyWPtr, connection);
944
}
945
cw_monero/lib/monero_wallet_service.dart
+37
-20
@@ -1,5 +1,7 @@
1
+import 'dart:async';
2
import 'dart:ffi';
3
import 'dart:io';
4
+import 'dart:isolate';
5
6
import 'package:collection/collection.dart';
7
import 'package:cw_core/get_height_by_date.dart';
@@ -20,6 +22,7 @@ import 'package:cw_monero/ledger.dart';
22
import 'package:cw_monero/monero_wallet.dart';
23
import 'package:hive/hive.dart';
24
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
25
+import 'package:monero/src/monero.dart' as m;
26
import 'package:monero/monero.dart' as monero;
27
import 'package:polyseed/polyseed.dart';
28
@@ -139,7 +142,7 @@ class MoneroWalletService extends WalletService<
142
overrideHeight: heightOverride, passphrase: credentials.passphrase);
143
}
144
142
- await monero_wallet_manager.createWallet(
145
+ monero_wallet_manager.createWallet(
146
path: path,
147
password: credentials.password!,
148
language: credentials.language,
@@ -179,7 +182,7 @@ class MoneroWalletService extends WalletService<
182
if (walletFilesExist(path)) await repairOldAndroidWallet(name);
183
184
await monero_wallet_manager
182
- .openWalletAsync({'path': path, 'password': password});
185
+ .openWallet(path: path, password: password);
186
final walletInfo = walletInfoSource.values
187
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
188
final wallet = MoneroWallet(
@@ -217,13 +220,23 @@ class MoneroWalletService extends WalletService<
220
if (openedWalletsByPath["$path/$wallet"] != null) {
221
// NOTE: this is realistically only required on windows.
222
printV("closing wallet");
220
- final wmaddr = wmPtr.address;
221
- final waddr = openedWalletsByPath["$path/$wallet"]!.address;
222
- // await Isolate.run(() {
223
- monero.WalletManager_closeWallet(
224
- Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false);
225
- // });
223
+ final w = openedWalletsByPath["$path/$wallet"]!;
224
+ final wmaddr = wmPtr.ffiAddress();
225
+ final waddr = w.ffiAddress();
226
openedWalletsByPath.remove("$path/$wallet");
227
+ if (Platform.isWindows) {
228
+ await Isolate.run(() {
229
+ monero.WalletManager_closeWallet(
230
+ Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
231
+ monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
232
+ });
233
+ } else {
234
+ unawaited(Isolate.run(() {
235
+ monero.WalletManager_closeWallet(
236
+ Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
237
+ monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
238
+ }));
239
+ }
240
printV("wallet closed");
241
}
242
@@ -263,7 +276,7 @@ class MoneroWalletService extends WalletService<
276
{bool? isTestnet}) async {
277
try {
278
final path = await pathForWallet(name: credentials.name, type: getType());
266
- await monero_wallet_manager.restoreFromKeys(
279
+ monero_wallet_manager.restoreWalletFromKeys(
280
path: path,
281
password: credentials.password!,
282
language: credentials.language,
@@ -293,9 +306,13 @@ class MoneroWalletService extends WalletService<
306
final password = credentials.password;
307
final height = credentials.height;
308
296
- if (wptr == null) monero_wallet_manager.createWalletPointer();
309
+ if (currentWallet == null) {
310
+ final tmpWptr = monero_wallet_manager.createWalletPointer();
311
+ enableLedgerExchange(tmpWptr, credentials.ledgerConnection);
312
+ } else {
313
+ enableLedgerExchange(currentWallet!, credentials.ledgerConnection);
314
+ }
315
298
- enableLedgerExchange(wptr!, credentials.ledgerConnection);
316
await monero_wallet_manager.restoreWalletFromHardwareWallet(
317
path: path,
318
password: password!,
@@ -352,7 +369,7 @@ class MoneroWalletService extends WalletService<
369
try {
370
final path = await pathForWallet(name: credentials.name, type: getType());
371
355
- monero_wallet_manager.restoreFromSeed(
372
+ monero_wallet_manager.restoreWalletFromSeedSync(
373
path: path,
374
password: credentials.password!,
375
passphrase: credentials.passphrase,
@@ -393,7 +410,7 @@ class MoneroWalletService extends WalletService<
410
walletInfo.isRecovery = true;
411
walletInfo.restoreHeight = height;
412
396
- monero_wallet_manager.restoreFromSeed(
413
+ monero_wallet_manager.restoreWalletFromSeedSync(
414
path: path,
415
password: password,
416
passphrase: '',
@@ -401,12 +418,12 @@ class MoneroWalletService extends WalletService<
418
restoreHeight: height,
419
);
420
404
- monero.Wallet_setCacheAttribute(wptr!,
421
+ currentWallet!.setCacheAttribute(
422
key: "cakewallet.seed.bip39", value: mnemonic);
406
- monero.Wallet_setCacheAttribute(wptr!,
423
+ currentWallet!.setCacheAttribute(
424
key: "cakewallet.passphrase", value: passphrase ?? '');
425
409
- monero.Wallet_store(wptr!);
426
+ currentWallet!.store();
427
428
final wallet = MoneroWallet(
429
walletInfo: walletInfo,
@@ -472,7 +489,7 @@ class MoneroWalletService extends WalletService<
489
walletInfo.isRecovery = true;
490
walletInfo.restoreHeight = height;
491
475
- await monero_wallet_manager.restoreFromSpendKey(
492
+ monero_wallet_manager.restoreWalletFromSpendKeySync(
493
path: path,
494
password: password,
495
seed: seed,
@@ -481,8 +498,8 @@ class MoneroWalletService extends WalletService<
498
spendKey: spendKey);
499
500
484
- monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
485
- monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase??'');
501
+ currentWallet!.setCacheAttribute(key: "cakewallet.seed", value: seed);
502
+ currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: passphrase??'');
503
504
final wallet = MoneroWallet(
505
walletInfo: walletInfo,
@@ -529,7 +546,7 @@ class MoneroWalletService extends WalletService<
546
if (walletFilesExist(path)) await repairOldAndroidWallet(name);
547
548
await monero_wallet_manager
532
- .openWalletAsync({'path': path, 'password': password});
549
+ .openWallet(path: path, password: password);
550
final walletInfo = walletInfoSource.values
551
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
552
final wallet = MoneroWallet(
cw_monero/pubspec.lock
+2
-2
@@ -573,8 +573,8 @@ packages:
573
dependency: "direct main"
574
description:
575
path: "impls/monero.dart"
576
- ref: "84e52393e395d75f449bcd81e23028889538118f"
577
- resolved-ref: "84e52393e395d75f449bcd81e23028889538118f"
576
+ ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
577
+ resolved-ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
578
url: "https://github.com/mrcyjanek/monero_c"
579
source: git
580
version: "0.0.0"
cw_monero/pubspec.yaml
+1
-1
@@ -27,7 +27,7 @@ dependencies:
27
monero:
28
git:
29
url: https://github.com/mrcyjanek/monero_c
30
- ref: 84e52393e395d75f449bcd81e23028889538118f
30
+ ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
31
path: impls/monero.dart
32
mutex: ^3.1.0
33
ledger_flutter_plus: ^1.4.1
cw_wownero/pubspec.lock
+2
-2
@@ -480,8 +480,8 @@ packages:
480
dependency: "direct main"
481
description:
482
path: "impls/monero.dart"
483
- ref: "84e52393e395d75f449bcd81e23028889538118f"
484
- resolved-ref: "84e52393e395d75f449bcd81e23028889538118f"
483
+ ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
484
+ resolved-ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
485
url: "https://github.com/mrcyjanek/monero_c"
486
source: git
487
version: "0.0.0"
cw_wownero/pubspec.yaml
+1
-1
@@ -25,7 +25,7 @@ dependencies:
25
monero:
26
git:
27
url: https://github.com/mrcyjanek/monero_c
28
- ref: 84e52393e395d75f449bcd81e23028889538118f # monero_c hash
28
+ ref: b335585a7fb94b315eb52bd88f2da6d3489fa508 # monero_c hash
29
path: impls/monero.dart
30
mutex: ^3.1.0
31
cw_zano/pubspec.lock
+2
-2
@@ -485,8 +485,8 @@ packages:
485
dependency: "direct main"
486
description:
487
path: "impls/monero.dart"
488
- ref: "84e52393e395d75f449bcd81e23028889538118f"
489
- resolved-ref: "84e52393e395d75f449bcd81e23028889538118f"
488
+ ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
489
+ resolved-ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
490
url: "https://github.com/mrcyjanek/monero_c"
491
source: git
492
version: "0.0.0"
cw_zano/pubspec.yaml
+1
-1
@@ -26,7 +26,7 @@ dependencies:
26
monero:
27
git:
28
url: https://github.com/mrcyjanek/monero_c
29
- ref: 84e52393e395d75f449bcd81e23028889538118f # monero_c hash
29
+ ref: b335585a7fb94b315eb52bd88f2da6d3489fa508 # monero_c hash
30
path: impls/monero.dart
31
dev_dependencies:
32
flutter_test:
ios/Podfile.lock
+27
-29
@@ -208,42 +208,40 @@ EXTERNAL SOURCES:
208
:path: ".symlinks/plugins/wakelock_plus/ios"
209
210
SPEC CHECKSUMS:
211
- connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
211
+ connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
212
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
213
- cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
214
- cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
215
- device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
216
- device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
217
- devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
213
+ cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
214
+ cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85
215
+ device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f
216
+ device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
217
+ devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8
218
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
219
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
220
- fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc
221
- file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
220
+ fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3
221
+ file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
222
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
223
- flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
224
- flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
225
- flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
226
- flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
227
- flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
228
- fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
229
- in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
230
- integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
223
+ flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
224
+ flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f
225
+ flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4
226
+ flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
227
+ fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
228
+ in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457
229
+ integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
230
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
232
- package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
233
- path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
234
- permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
235
- reown_yttrium: c0e87e5965fa60a3559564cc35cffbba22976089
231
+ package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
232
+ path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
233
+ permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
234
+ ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
235
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
237
- sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
238
- share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
239
- shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
240
- sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
236
+ sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b
237
+ share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
238
+ shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
239
+ sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5
240
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
242
- uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
243
- universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
244
- url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
245
- wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e
246
- YttriumWrapper: 31e937fe9fbe0f1314d2ca6be9ce9b379a059966
241
+ uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
242
+ universal_ble: ff19787898040d721109c6324472e5dd4bc86adc
243
+ url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
244
+ wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
245
246
PODFILE CHECKSUM: 5296465b1c6d14d506230356756826012f65d97a
247
lib/core/wallet_loading_service.dart
+22
-17
@@ -32,23 +32,28 @@ class WalletLoadingService {
32
33
Future<void> renameWallet(WalletType type, String name, String newName,
34
{String? password}) async {
35
- final walletService = walletServiceFactory.call(type);
36
- final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
37
-
38
- // Save the current wallet's password to the new wallet name's key
39
- await keyService.saveWalletPassword(walletName: newName, password: walletPassword);
40
- // Delete previous wallet name from keyService to keep only new wallet's name
41
- // otherwise keeps duplicate (old and new names)
42
- await keyService.deleteWalletPassword(walletName: name);
43
-
44
- await walletService.rename(name, walletPassword, newName);
45
-
46
- // set shared preferences flag based on previous wallet name
47
- if (type == WalletType.monero) {
48
- final oldNameKey = PreferencesKey.moneroWalletUpdateV1Key(name);
49
- final isPasswordUpdated = sharedPreferences.getBool(oldNameKey) ?? false;
50
- final newNameKey = PreferencesKey.moneroWalletUpdateV1Key(newName);
51
- await sharedPreferences.setBool(newNameKey, isPasswordUpdated);
35
+ try {
36
+ final walletService = walletServiceFactory.call(type);
37
+ final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
38
+
39
+ // Save the current wallet's password to the new wallet name's key
40
+ await keyService.saveWalletPassword(walletName: newName, password: walletPassword);
41
+
42
+ await walletService.rename(name, walletPassword, newName);
43
+ // Delete previous wallet name from keyService to keep only new wallet's name
44
+ // otherwise keeps duplicate (old and new names)
45
+ await keyService.deleteWalletPassword(walletName: name);
46
+
47
+ // set shared preferences flag based on previous wallet name
48
+ if (type == WalletType.monero) {
49
+ final oldNameKey = PreferencesKey.moneroWalletUpdateV1Key(name);
50
+ final isPasswordUpdated = sharedPreferences.getBool(oldNameKey) ?? false;
51
+ final newNameKey = PreferencesKey.moneroWalletUpdateV1Key(newName);
52
+ await sharedPreferences.setBool(newNameKey, isPasswordUpdated);
53
+ }
54
+ } catch (error, stack) {
55
+ await ExceptionHandler.resetLastPopupDate();
56
+ await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
57
}
58
}
59
lib/monero/cw_monero.dart
+2
-2
@@ -39,14 +39,14 @@ class CWMoneroAccountList extends MoneroAccountList {
39
@override
40
Future<void> addAccount(Object wallet, {required String label}) async {
41
final moneroWallet = wallet as MoneroWallet;
42
- await moneroWallet.walletAddresses.accountList.addAccount(label: label);
42
+ moneroWallet.walletAddresses.accountList.addAccount(label: label);
43
}
44
45
@override
46
Future<void> setLabelAccount(Object wallet,
47
{required int accountIndex, required String label}) async {
48
final moneroWallet = wallet as MoneroWallet;
49
- await moneroWallet.walletAddresses.accountList
49
+ moneroWallet.walletAddresses.accountList
50
.setLabelAccount(accountIndex: accountIndex, label: label);
51
}
52
}
lib/view_model/dashboard/dashboard_view_model.dart
+26
-6
@@ -271,10 +271,19 @@ abstract class DashboardViewModelBase with Store {
271
});
272
273
_transactionDisposer?.reaction.dispose();
274
- _transactionDisposer = reaction(
275
- (_) => appStore.wallet!.transactionHistory.transactions.length,
276
- _transactionDisposerCallback,
277
- );
274
+ _transactionDisposer = reaction((_) {
275
+ final length = appStore.wallet!.transactionHistory.transactions.length;
276
+ if (length == 0) {
277
+ return 0;
278
+ }
279
+ int confirmations = 1;
280
+ if (![WalletType.solana, WalletType.tron].contains(wallet.type)) {
281
+ try {
282
+ confirmations = appStore.wallet!.transactionHistory.transactions.values.first.confirmations + 1;
283
+ } catch (_) {}
284
+ }
285
+ return length * confirmations;
286
+ }, _transactionDisposerCallback);
287
288
if (hasSilentPayments) {
289
silentPaymentsScanningActive = bitcoin!.getScanningActive(wallet);
@@ -891,8 +900,19 @@ abstract class DashboardViewModelBase with Store {
900
901
_transactionDisposer?.reaction.dispose();
902
894
- _transactionDisposer = reaction((_) => appStore.wallet!.transactionHistory.transactions.length,
895
- _transactionDisposerCallback);
903
+ _transactionDisposer = reaction((_) {
904
+ final length = appStore.wallet!.transactionHistory.transactions.length;
905
+ if (length == 0) {
906
+ return 0;
907
+ }
908
+ int confirmations = 1;
909
+ if (![WalletType.solana, WalletType.tron].contains(wallet.type)) {
910
+ try {
911
+ confirmations = appStore.wallet!.transactionHistory.transactions.values.first.confirmations + 1;
912
+ } catch (_) {}
913
+ }
914
+ return length * confirmations;
915
+ }, _transactionDisposerCallback);
916
}
917
918
@action
lib/view_model/send/send_view_model.dart
+3
-1
@@ -1,3 +1,5 @@
1
+import 'dart:async';
2
+
3
import 'package:cake_wallet/bitcoin/bitcoin.dart';
4
import 'package:cake_wallet/core/address_validator.dart';
5
import 'package:cake_wallet/core/amount_validator.dart';
@@ -591,7 +593,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
593
}
594
final sharedPreferences = await SharedPreferences.getInstance();
595
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name), DateTime.now().add(Duration(minutes: 1)).toIso8601String());
594
-
596
+ unawaited(wallet.fetchTransactions());
597
state = TransactionCommitted();
598
} catch (e) {
599
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
scripts/prepare_moneroc.sh
+1
-1
@@ -8,7 +8,7 @@ if [[ ! -d "monero_c/.git" ]];
8
then
9
git clone https://github.com/mrcyjanek/monero_c --branch master monero_c
10
cd monero_c
11
- git checkout 84e52393e395d75f449bcd81e23028889538118f
11
+ git checkout b335585a7fb94b315eb52bd88f2da6d3489fa508
12
git reset --hard
13
git submodule update --init --force --recursive
14
./apply_patches.sh monero