concurrent xmr/wow wallets

This commit is contained in:
julian 2024-09-20 09:38:05 -06:00 committed by julian-CStack
parent cdd9e078f8
commit 642f0906b8
8 changed files with 150 additions and 227 deletions

@ -1 +1 @@
Subproject commit 7186b0bb936428cba441b69f77b508d007c50fb2 Subproject commit fd9892cfa3ab85d50354f334a18a537b4af7d00e

View file

@ -20,8 +20,6 @@ import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_libmonero/monero/monero.dart';
import 'package:flutter_libmonero/wownero/wownero.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -237,9 +235,6 @@ void main(List<String> args) async {
} }
} }
monero.onStartup();
wownero.onStartup();
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
// overlays: [SystemUiOverlay.bottom]); // overlays: [SystemUiOverlay.bottom]);
unawaited(NotificationApi.init()); unawaited(NotificationApi.init());

View file

@ -8,6 +8,8 @@
* *
*/ */
import 'package:flutter/foundation.dart';
import '../../../../utilities/logger.dart'; import '../../../../utilities/logger.dart';
class UpdatedInBackgroundEvent { class UpdatedInBackgroundEvent {
@ -15,9 +17,11 @@ class UpdatedInBackgroundEvent {
String walletId; String walletId;
UpdatedInBackgroundEvent(this.message, this.walletId) { UpdatedInBackgroundEvent(this.message, this.walletId) {
Logging.instance.log( if (kDebugMode) {
"UpdatedInBackgroundEvent fired with message: $message", Logging.instance.log(
level: LogLevel.Info, "UpdatedInBackgroundEvent fired with message: $message",
); level: LogLevel.Info,
);
}
} }
} }

View file

@ -1,4 +1,4 @@
import 'package:cw_wownero/api/wallet.dart' as wownero_wallet; import 'package:monero/wownero.dart' as wownero;
import '../../../models/node_model.dart'; import '../../../models/node_model.dart';
import '../../../utilities/default_nodes.dart'; import '../../../utilities/default_nodes.dart';
@ -48,7 +48,7 @@ class Wownero extends CryptonoteCurrency {
@override @override
bool validateAddress(String address) { bool validateAddress(String address) {
return wownero_wallet.addressValid(address); return wownero.Wallet_addressValid(address, 0);
} }
@override @override

View file

@ -13,6 +13,7 @@ import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart'; import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_monero/monero_wallet.dart'; import 'package:cw_monero/monero_wallet.dart';
import 'package:cw_monero/monero_wallet_service.dart';
import 'package:cw_monero/pending_monero_transaction.dart'; import 'package:cw_monero/pending_monero_transaction.dart';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:flutter_libmonero/core/wallet_creation_service.dart'; import 'package:flutter_libmonero/core/wallet_creation_service.dart';
@ -73,9 +74,15 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
} }
@override
MoneroWalletBase? cwWalletBase;
@override
MoneroWalletService? cwWalletService;
@override @override
Address addressFor({required int index, int account = 0}) { Address addressFor({required int index, int account = 0}) {
final String address = (CwBasedInterface.cwWalletBase as MoneroWalletBase) final String address = (cwWalletBase as MoneroWalletBase)
.getTransactionAddress(account, index); .getTransactionAddress(account, index);
final newReceivingAddress = Address( final newReceivingAddress = Address(
@ -91,22 +98,8 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
return newReceivingAddress; return newReceivingAddress;
} }
@override
Future<void> exitCwWallet() async {
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewBlock = null;
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewTransaction =
null;
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.syncStatusChanged =
null;
await (CwBasedInterface.cwWalletBase as MoneroWalletBase?)
?.save(prioritySave: true);
}
@override @override
Future<void> open() async { Future<void> open() async {
// await any previous exit
await CwBasedInterface.exitMutex.protect(() async {});
String? password; String? password;
try { try {
password = await cwKeysStorage.getWalletPassword(walletName: walletId); password = await cwKeysStorage.getWalletPassword(walletName: walletId);
@ -114,18 +107,20 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
throw Exception("Password not found $e, $s"); throw Exception("Password not found $e, $s");
} }
CwBasedInterface.cwWalletBase?.close(); bool wasNull = false;
CwBasedInterface.cwWalletBase = (await CwBasedInterface.cwWalletService!
.openWallet(walletId, password)) as MoneroWalletBase;
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewBlock = if (cwWalletBase == null) {
onNewBlock; wasNull = true;
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewTransaction = // cwWalletBaseT?.close();
onNewTransaction; cwWalletBase ??= (await cwWalletService!.openWallet(walletId, password))
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.syncStatusChanged = as MoneroWalletBase;
syncStatusChanged;
await updateNode(); cwWalletBase?.onNewBlock ??= onNewBlock;
cwWalletBase?.onNewTransaction ??= onNewTransaction;
cwWalletBase?.syncStatusChanged ??= syncStatusChanged;
await updateNode();
}
Address? currentAddress = await getCurrentReceivingAddress(); Address? currentAddress = await getCurrentReceivingAddress();
if (currentAddress == null) { if (currentAddress == null) {
@ -139,19 +134,23 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
} }
await CwBasedInterface.cwWalletBase?.startSync(); if (wasNull) {
await cwWalletBase?.startSync();
} else {
cwWalletBase?.wallet.startListeners();
}
unawaited(refresh()); unawaited(refresh());
autoSaveTimer?.cancel(); autoSaveTimer?.cancel();
autoSaveTimer = Timer.periodic( autoSaveTimer = Timer.periodic(
const Duration(seconds: 193), const Duration(seconds: 193),
(_) async => await CwBasedInterface.cwWalletBase?.save(), (_) async => await cwWalletBase?.save(),
); );
} }
@override @override
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async { Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
if (CwBasedInterface.cwWalletBase == null || if (cwWalletBase == null || cwWalletBase?.syncStatus is! SyncedSyncStatus) {
CwBasedInterface.cwWalletBase?.syncStatus is! SyncedSyncStatus) {
return Amount.zeroWith( return Amount.zeroWith(
fractionDigits: cryptoCurrency.fractionDigits, fractionDigits: cryptoCurrency.fractionDigits,
); );
@ -179,7 +178,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
int approximateFee = 0; int approximateFee = 0;
await estimateFeeMutex.protect(() async { await estimateFeeMutex.protect(() async {
approximateFee = CwBasedInterface.cwWalletBase!.calculateEstimatedFee( approximateFee = cwWalletBase!.calculateEstimatedFee(
priority, priority,
amount.raw.toInt(), amount.raw.toInt(),
); );
@ -193,9 +192,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<bool> pingCheck() async { Future<bool> pingCheck() async {
return await (CwBasedInterface.cwWalletBase as MoneroWalletBase?) return await cwWalletBase?.isConnected() ?? false;
?.isConnected() ??
false;
} }
@override @override
@ -212,7 +209,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
} }
if (_requireMutex) { if (_requireMutex) {
await _torConnectingLock.protect(() async { await _torConnectingLock.protect(() async {
await CwBasedInterface.cwWalletBase?.connectToNode( await cwWalletBase?.connectToNode(
node: Node( node: Node(
uri: "$host:${node.port}", uri: "$host:${node.port}",
type: WalletType.monero, type: WalletType.monero,
@ -224,7 +221,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
}); });
} else { } else {
await CwBasedInterface.cwWalletBase?.connectToNode( await cwWalletBase?.connectToNode(
node: Node( node: Node(
uri: "$host:${node.port}", uri: "$host:${node.port}",
type: WalletType.monero, type: WalletType.monero,
@ -241,11 +238,9 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<CWKeyData?> getKeys() async { Future<CWKeyData?> getKeys() async {
final base = (CwBasedInterface.cwWalletBase as MoneroWalletBase?); final base = cwWalletBase;
if (base == null || if (base == null || base.walletInfo.name != walletId) {
base.walletInfo.name != walletId ||
CwBasedInterface.exitMutex.isLocked) {
return null; return null;
} }
@ -260,11 +255,9 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<void> updateTransactions() async { Future<void> updateTransactions() async {
final base = (CwBasedInterface.cwWalletBase as MoneroWalletBase?); final base = cwWalletBase;
if (base == null || if (base == null || base.walletInfo.name != walletId) {
base.walletInfo.name != walletId ||
CwBasedInterface.exitMutex.isLocked) {
return; return;
} }
await base.updateTransactions(); await base.updateTransactions();
@ -311,9 +304,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
if (tx.value.direction == TransactionDirection.incoming) { if (tx.value.direction == TransactionDirection.incoming) {
final addressInfo = tx.value.additionalInfo; final addressInfo = tx.value.additionalInfo;
final addressString = final addressString = cwWalletBase?.getTransactionAddress(
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)
?.getTransactionAddress(
addressInfo!['accountIndex'] as int, addressInfo!['accountIndex'] as int,
addressInfo['addressIndex'] as int, addressInfo['addressIndex'] as int,
); );
@ -388,12 +379,11 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<void> init({bool? isRestore}) async { Future<void> init({bool? isRestore}) async {
await CwBasedInterface.exitMutex.protect(() async {}); cwWalletService ??= xmr_dart.monero
.createMoneroWalletService(DB.instance.moneroWalletInfoBox)
as MoneroWalletService;
CwBasedInterface.cwWalletService = xmr_dart.monero if (!(await cwWalletService!.isWalletExist(walletId)) &&
.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
if (!(await CwBasedInterface.cwWalletService!.isWalletExit(walletId)) &&
isRestore != true) { isRestore != true) {
WalletInfo walletInfo; WalletInfo walletInfo;
WalletCredentials credentials; WalletCredentials credentials;
@ -422,10 +412,10 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
final _walletCreationService = WalletCreationService( final _walletCreationService = WalletCreationService(
secureStorage: secureStorageInterface, secureStorage: secureStorageInterface,
walletService: CwBasedInterface.cwWalletService, walletService: cwWalletService!,
keyService: cwKeysStorage, keyService: cwKeysStorage,
type: WalletType.monero,
); );
_walletCreationService.type = WalletType.monero;
// To restore from a seed // To restore from a seed
final wallet = await _walletCreationService.create(credentials); final wallet = await _walletCreationService.create(credentials);
@ -459,7 +449,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
wallet.close(); wallet.close();
} catch (e, s) { } catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal); Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
CwBasedInterface.cwWalletBase?.close(); cwWalletBase?.close();
} }
await updateNode(); await updateNode();
} }
@ -469,17 +459,14 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<void> recover({required bool isRescan}) async { Future<void> recover({required bool isRescan}) async {
await CwBasedInterface.exitMutex.protect(() async {});
if (isRescan) { if (isRescan) {
await refreshMutex.protect(() async { await refreshMutex.protect(() async {
// clear blockchain info // clear blockchain info
await mainDB.deleteWalletBlockchainData(walletId); await mainDB.deleteWalletBlockchainData(walletId);
final restoreHeight = final restoreHeight = cwWalletBase?.walletInfo.restoreHeight;
CwBasedInterface.cwWalletBase?.walletInfo.restoreHeight;
highestPercentCached = 0; highestPercentCached = 0;
await CwBasedInterface.cwWalletBase?.rescan(height: restoreHeight ?? 0); await cwWalletBase?.rescan(height: restoreHeight ?? 0);
}); });
unawaited(refresh()); unawaited(refresh());
return; return;
@ -501,8 +488,9 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
isar: mainDB.isar, isar: mainDB.isar,
); );
CwBasedInterface.cwWalletService = xmr_dart.monero cwWalletService = xmr_dart.monero
.createMoneroWalletService(DB.instance.moneroWalletInfoBox); .createMoneroWalletService(DB.instance.moneroWalletInfoBox)
as MoneroWalletService;
WalletInfo walletInfo; WalletInfo walletInfo;
WalletCredentials credentials; WalletCredentials credentials;
final String name = walletId; final String name = walletId;
@ -531,10 +519,10 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
final cwWalletCreationService = WalletCreationService( final cwWalletCreationService = WalletCreationService(
secureStorage: secureStorageInterface, secureStorage: secureStorageInterface,
walletService: CwBasedInterface.cwWalletService, walletService: cwWalletService!,
keyService: cwKeysStorage, keyService: cwKeysStorage,
type: WalletType.monero,
); );
cwWalletCreationService.type = WalletType.monero;
// To restore from a seed // To restore from a seed
final wallet = final wallet =
await cwWalletCreationService.restoreFromSeed(credentials); await cwWalletCreationService.restoreFromSeed(credentials);
@ -559,15 +547,15 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
isar: mainDB.isar, isar: mainDB.isar,
); );
} }
CwBasedInterface.cwWalletBase?.close(); cwWalletBase?.close();
CwBasedInterface.cwWalletBase = wallet as MoneroWalletBase; cwWalletBase = wallet as MoneroWalletBase;
} catch (e, s) { } catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal); Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
} }
await updateNode(); await updateNode();
await CwBasedInterface.cwWalletBase?.rescan(height: credentials.height); await cwWalletBase?.rescan(height: credentials.height);
CwBasedInterface.cwWalletBase?.close(); cwWalletBase?.close();
} catch (e, s) { } catch (e, s) {
Logging.instance.log( Logging.instance.log(
"Exception rethrown from recoverFromMnemonic(): $e\n$s", "Exception rethrown from recoverFromMnemonic(): $e\n$s",
@ -610,7 +598,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
final List<monero_output.Output> outputs = []; final List<monero_output.Output> outputs = [];
for (final recipient in txData.recipients!) { for (final recipient in txData.recipients!) {
final output = monero_output.Output(CwBasedInterface.cwWalletBase!); final output = monero_output.Output(cwWalletBase!);
output.address = recipient.address; output.address = recipient.address;
output.sendAll = isSendAll; output.sendAll = isSendAll;
final String amountToSend = recipient.amount.decimal.toString(); final String amountToSend = recipient.amount.decimal.toString();
@ -625,8 +613,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
await prepareSendMutex.protect(() async { await prepareSendMutex.protect(() async {
awaitPendingTransaction = awaitPendingTransaction = cwWalletBase!.createTransaction(tmp);
CwBasedInterface.cwWalletBase!.createTransaction(tmp);
}); });
} catch (e, s) { } catch (e, s) {
Logging.instance.log( Logging.instance.log(
@ -694,13 +681,8 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<Amount> get availableBalance async { Future<Amount> get availableBalance async {
try { try {
if (CwBasedInterface.exitMutex.isLocked) {
throw Exception("Exit in progress");
}
int runningBalance = 0; int runningBalance = 0;
for (final entry in (CwBasedInterface.cwWalletBase as MoneroWalletBase?)! for (final entry in cwWalletBase!.balance!.entries) {
.balance!
.entries) {
runningBalance += entry.value.unlockedBalance; runningBalance += entry.value.unlockedBalance;
} }
return Amount( return Amount(
@ -715,13 +697,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<Amount> get totalBalance async { Future<Amount> get totalBalance async {
try { try {
if (CwBasedInterface.exitMutex.isLocked) { final balanceEntries = cwWalletBase?.balance?.entries;
throw Exception("Exit in progress");
}
final balanceEntries =
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)
?.balance
?.entries;
if (balanceEntries != null) { if (balanceEntries != null) {
int bal = 0; int bal = 0;
for (final element in balanceEntries) { for (final element in balanceEntries) {
@ -732,10 +708,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
fractionDigits: cryptoCurrency.fractionDigits, fractionDigits: cryptoCurrency.fractionDigits,
); );
} else { } else {
final transactions = final transactions = cwWalletBase!.transactionHistory!.transactions;
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)!
.transactionHistory!
.transactions;
int transactionBalance = 0; int transactionBalance = 0;
for (final tx in transactions!.entries) { for (final tx in transactions!.entries) {
if (tx.value.direction == TransactionDirection.incoming) { if (tx.value.direction == TransactionDirection.incoming) {

View file

@ -12,9 +12,9 @@ import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart'; import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_wownero/api/account_list.dart';
import 'package:cw_wownero/pending_wownero_transaction.dart'; import 'package:cw_wownero/pending_wownero_transaction.dart';
import 'package:cw_wownero/wownero_wallet.dart'; import 'package:cw_wownero/wownero_wallet.dart';
import 'package:cw_wownero/wownero_wallet_service.dart';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:flutter_libmonero/core/wallet_creation_service.dart'; import 'package:flutter_libmonero/core/wallet_creation_service.dart';
import 'package:flutter_libmonero/view_model/send/output.dart' import 'package:flutter_libmonero/view_model/send/output.dart'
@ -76,9 +76,15 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
} }
@override
WowneroWalletBase? cwWalletBase;
@override
WowneroWalletService? cwWalletService;
@override @override
Address addressFor({required int index, int account = 0}) { Address addressFor({required int index, int account = 0}) {
final String address = (CwBasedInterface.cwWalletBase as WowneroWalletBase) final String address = (cwWalletBase as WowneroWalletBase)
.getTransactionAddress(account, index); .getTransactionAddress(account, index);
final newReceivingAddress = Address( final newReceivingAddress = Address(
@ -96,8 +102,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async { Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
if (CwBasedInterface.cwWalletBase == null || if (cwWalletBase == null || cwWalletBase?.syncStatus is! SyncedSyncStatus) {
CwBasedInterface.cwWalletBase?.syncStatus is! SyncedSyncStatus) {
return Amount.zeroWith( return Amount.zeroWith(
fractionDigits: cryptoCurrency.fractionDigits, fractionDigits: cryptoCurrency.fractionDigits,
); );
@ -152,7 +157,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
// unsure why this delay? // unsure why this delay?
await Future<void>.delayed(const Duration(milliseconds: 500)); await Future<void>.delayed(const Duration(milliseconds: 500));
} catch (e) { } catch (e) {
approximateFee = CwBasedInterface.cwWalletBase!.calculateEstimatedFee( approximateFee = cwWalletBase!.calculateEstimatedFee(
priority, priority,
amount.raw.toInt(), amount.raw.toInt(),
); );
@ -172,9 +177,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<bool> pingCheck() async { Future<bool> pingCheck() async {
return await (CwBasedInterface.cwWalletBase as WowneroWalletBase?) return await cwWalletBase?.isConnected() ?? false;
?.isConnected() ??
false;
} }
@override @override
@ -188,7 +191,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
} }
if (_requireMutex) { if (_requireMutex) {
await _torConnectingLock.protect(() async { await _torConnectingLock.protect(() async {
await CwBasedInterface.cwWalletBase?.connectToNode( await cwWalletBase?.connectToNode(
node: Node( node: Node(
uri: "$host:${node.port}", uri: "$host:${node.port}",
type: WalletType.wownero, type: WalletType.wownero,
@ -200,7 +203,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
}); });
} else { } else {
await CwBasedInterface.cwWalletBase?.connectToNode( await cwWalletBase?.connectToNode(
node: Node( node: Node(
uri: "$host:${node.port}", uri: "$host:${node.port}",
type: WalletType.wownero, type: WalletType.wownero,
@ -217,11 +220,9 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<CWKeyData?> getKeys() async { Future<CWKeyData?> getKeys() async {
final base = (CwBasedInterface.cwWalletBase as WowneroWalletBase?); final base = cwWalletBase;
if (base == null || if (base == null || base.walletInfo.name != walletId) {
base.walletInfo.name != walletId ||
CwBasedInterface.exitMutex.isLocked) {
return null; return null;
} }
@ -236,11 +237,9 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<void> updateTransactions() async { Future<void> updateTransactions() async {
final base = (CwBasedInterface.cwWalletBase as WowneroWalletBase?); final base = cwWalletBase;
if (base == null || if (base == null || base.walletInfo.name != walletId) {
base.walletInfo.name != walletId ||
CwBasedInterface.exitMutex.isLocked) {
return; return;
} }
await base.updateTransactions(); await base.updateTransactions();
@ -287,9 +286,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
if (tx.value.direction == TransactionDirection.incoming) { if (tx.value.direction == TransactionDirection.incoming) {
final addressInfo = tx.value.additionalInfo; final addressInfo = tx.value.additionalInfo;
final addressString = final addressString = cwWalletBase?.getTransactionAddress(
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)
?.getTransactionAddress(
addressInfo!['accountIndex'] as int, addressInfo!['accountIndex'] as int,
addressInfo['addressIndex'] as int, addressInfo['addressIndex'] as int,
); );
@ -364,11 +361,11 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<void> init({bool? isRestore}) async { Future<void> init({bool? isRestore}) async {
await CwBasedInterface.exitMutex.protect(() async {}); cwWalletService = wow_dart.wownero
CwBasedInterface.cwWalletService = wow_dart.wownero .createWowneroWalletService(DB.instance.moneroWalletInfoBox)
.createWowneroWalletService(DB.instance.moneroWalletInfoBox); as WowneroWalletService;
if (!(await CwBasedInterface.cwWalletService!.isWalletExit(walletId)) && if (!(await cwWalletService!.isWalletExist(walletId)) &&
isRestore != true) { isRestore != true) {
WalletInfo walletInfo; WalletInfo walletInfo;
WalletCredentials credentials; WalletCredentials credentials;
@ -398,15 +395,16 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
final _walletCreationService = WalletCreationService( final _walletCreationService = WalletCreationService(
secureStorage: secureStorageInterface, secureStorage: secureStorageInterface,
walletService: CwBasedInterface.cwWalletService, walletService: cwWalletService!,
keyService: cwKeysStorage, keyService: cwKeysStorage,
type: WalletType.wownero,
); );
// _walletCreationService.changeWalletType();
_walletCreationService.type = WalletType.wownero;
// To restore from a seed // To restore from a seed
final wallet = await _walletCreationService.create(credentials); final wallet = await _walletCreationService.create(credentials)
as WowneroWalletBase;
final height = wownerodart.Wallet_getRefreshFromBlockHeight(wptr!); final height =
wownerodart.Wallet_getRefreshFromBlockHeight(wallet.wallet.wptr);
await info.updateRestoreHeight( await info.updateRestoreHeight(
newRestoreHeight: height, newRestoreHeight: height,
@ -433,7 +431,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
wallet.close(); wallet.close();
} catch (e, s) { } catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal); Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
CwBasedInterface.cwWalletBase?.close(); cwWalletBase?.close();
} }
await updateNode(); await updateNode();
} }
@ -443,9 +441,6 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<void> open() async { Future<void> open() async {
// await any previous exit
await CwBasedInterface.exitMutex.protect(() async {});
String? password; String? password;
try { try {
password = await cwKeysStorage.getWalletPassword(walletName: walletId); password = await cwKeysStorage.getWalletPassword(walletName: walletId);
@ -453,18 +448,20 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
throw Exception("Password not found $e, $s"); throw Exception("Password not found $e, $s");
} }
CwBasedInterface.cwWalletBase?.close(); bool wasNull = false;
CwBasedInterface.cwWalletBase = (await CwBasedInterface.cwWalletService!
.openWallet(walletId, password)) as WowneroWalletBase;
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)?.onNewBlock = if (cwWalletBase == null) {
onNewBlock; wasNull = true;
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)?.onNewTransaction = // cwWalletBaseT?.close();
onNewTransaction; cwWalletBase = (await cwWalletService!.openWallet(walletId, password))
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)?.syncStatusChanged = as WowneroWalletBase;
syncStatusChanged;
await updateNode(); cwWalletBase?.onNewBlock = onNewBlock;
cwWalletBase?.onNewTransaction = onNewTransaction;
cwWalletBase?.syncStatusChanged = syncStatusChanged;
await updateNode();
}
Address? currentAddress = await getCurrentReceivingAddress(); Address? currentAddress = await getCurrentReceivingAddress();
if (currentAddress == null) { if (currentAddress == null) {
@ -478,39 +475,29 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
} }
await (CwBasedInterface.cwWalletBase as WowneroWalletBase?)?.startSync(); if (wasNull) {
await cwWalletBase?.startSync();
} else {
cwWalletBase?.wallet.startListeners();
}
unawaited(refresh()); unawaited(refresh());
autoSaveTimer?.cancel();
autoSaveTimer = Timer.periodic( autoSaveTimer = Timer.periodic(
const Duration(seconds: 193), const Duration(seconds: 193),
(_) async => await CwBasedInterface.cwWalletBase?.save(), (_) async => await cwWalletBase?.save(),
); );
} }
@override
Future<void> exitCwWallet() async {
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)?.onNewBlock = null;
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)?.onNewTransaction =
null;
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)?.syncStatusChanged =
null;
await (CwBasedInterface.cwWalletBase as WowneroWalletBase?)
?.save(prioritySave: true);
}
@override @override
Future<void> recover({required bool isRescan}) async { Future<void> recover({required bool isRescan}) async {
await CwBasedInterface.exitMutex.protect(() async {});
if (isRescan) { if (isRescan) {
await refreshMutex.protect(() async { await refreshMutex.protect(() async {
// clear blockchain info // clear blockchain info
await mainDB.deleteWalletBlockchainData(walletId); await mainDB.deleteWalletBlockchainData(walletId);
final restoreHeight = final restoreHeight = cwWalletBase?.walletInfo.restoreHeight;
CwBasedInterface.cwWalletBase?.walletInfo.restoreHeight;
highestPercentCached = 0; highestPercentCached = 0;
await CwBasedInterface.cwWalletBase?.rescan(height: restoreHeight ?? 0); await cwWalletBase?.rescan(height: restoreHeight ?? 0);
}); });
unawaited(refresh()); unawaited(refresh());
return; return;
@ -534,12 +521,14 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
height = max(height, 0); height = max(height, 0);
} }
// TODO: info.updateRestoreHeight await info.updateRestoreHeight(
// await DB.instance newRestoreHeight: height,
// .put<dynamic>(boxName: walletId, key: "restoreHeight", value: height); isar: mainDB.isar,
);
CwBasedInterface.cwWalletService = wow_dart.wownero cwWalletService = wow_dart.wownero
.createWowneroWalletService(DB.instance.moneroWalletInfoBox); .createWowneroWalletService(DB.instance.moneroWalletInfoBox)
as WowneroWalletService;
WalletInfo walletInfo; WalletInfo walletInfo;
WalletCredentials credentials; WalletCredentials credentials;
final String name = walletId; final String name = walletId;
@ -569,14 +558,15 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
final cwWalletCreationService = WalletCreationService( final cwWalletCreationService = WalletCreationService(
secureStorage: secureStorageInterface, secureStorage: secureStorageInterface,
walletService: CwBasedInterface.cwWalletService, walletService: cwWalletService!,
keyService: cwKeysStorage, keyService: cwKeysStorage,
type: WalletType.wownero,
); );
cwWalletCreationService.type = WalletType.wownero;
// To restore from a seed // To restore from a seed
final wallet = await cwWalletCreationService final wallet = await cwWalletCreationService
.restoreFromSeed(credentials) as WowneroWalletBase; .restoreFromSeed(credentials) as WowneroWalletBase;
height = wownerodart.Wallet_getRefreshFromBlockHeight(wptr!); height =
wownerodart.Wallet_getRefreshFromBlockHeight(wallet.wallet.wptr);
walletInfo.address = wallet.walletAddresses.address; walletInfo.address = wallet.walletAddresses.address;
walletInfo.restoreHeight = height; walletInfo.restoreHeight = height;
await info.updateRestoreHeight( await info.updateRestoreHeight(
@ -585,8 +575,8 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
await DB.instance await DB.instance
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo); .add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
CwBasedInterface.cwWalletBase?.close(); cwWalletBase?.close();
CwBasedInterface.cwWalletBase = wallet; cwWalletBase = wallet;
if (walletInfo.address != null) { if (walletInfo.address != null) {
final newReceivingAddress = await getCurrentReceivingAddress() ?? final newReceivingAddress = await getCurrentReceivingAddress() ??
Address( Address(
@ -610,8 +600,8 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
} }
await updateNode(); await updateNode();
await CwBasedInterface.cwWalletBase?.rescan(height: credentials.height); await cwWalletBase?.rescan(height: credentials.height);
CwBasedInterface.cwWalletBase?.close(); cwWalletBase?.close();
} catch (e, s) { } catch (e, s) {
Logging.instance.log( Logging.instance.log(
"Exception rethrown from recoverFromMnemonic(): $e\n$s", "Exception rethrown from recoverFromMnemonic(): $e\n$s",
@ -654,8 +644,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
final List<wownero_output.Output> outputs = []; final List<wownero_output.Output> outputs = [];
for (final recipient in txData.recipients!) { for (final recipient in txData.recipients!) {
final output = final output = wownero_output.Output(cwWalletBase!);
wownero_output.Output(CwBasedInterface.cwWalletBase!);
output.address = recipient.address; output.address = recipient.address;
output.sendAll = isSendAll; output.sendAll = isSendAll;
final String amountToSend = recipient.amount.decimal.toString(); final String amountToSend = recipient.amount.decimal.toString();
@ -670,8 +659,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
); );
await prepareSendMutex.protect(() async { await prepareSendMutex.protect(() async {
awaitPendingTransaction = awaitPendingTransaction = cwWalletBase!.createTransaction(tmp);
CwBasedInterface.cwWalletBase!.createTransaction(tmp);
}); });
} catch (e, s) { } catch (e, s) {
Logging.instance.log( Logging.instance.log(
@ -739,14 +727,8 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<Amount> get availableBalance async { Future<Amount> get availableBalance async {
try { try {
if (CwBasedInterface.exitMutex.isLocked) {
throw Exception("Exit in progress");
}
int runningBalance = 0; int runningBalance = 0;
for (final entry in (CwBasedInterface.cwWalletBase as WowneroWalletBase?)! for (final entry in cwWalletBase!.balance!.entries) {
.balance!
.entries) {
runningBalance += entry.value.unlockedBalance; runningBalance += entry.value.unlockedBalance;
} }
return Amount( return Amount(
@ -761,13 +743,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
@override @override
Future<Amount> get totalBalance async { Future<Amount> get totalBalance async {
try { try {
if (CwBasedInterface.exitMutex.isLocked) { final balanceEntries = cwWalletBase?.balance?.entries;
throw Exception("Exit in progress");
}
final balanceEntries =
(CwBasedInterface.cwWalletBase as WowneroWalletBase?)
?.balance
?.entries;
if (balanceEntries != null) { if (balanceEntries != null) {
int bal = 0; int bal = 0;
for (final element in balanceEntries) { for (final element in balanceEntries) {
@ -778,8 +754,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
fractionDigits: cryptoCurrency.fractionDigits, fractionDigits: cryptoCurrency.fractionDigits,
); );
} else { } else {
final transactions = final transactions = cwWalletBase!.transactionHistory!.transactions;
CwBasedInterface.cwWalletBase!.transactionHistory!.transactions;
int transactionBalance = 0; int transactionBalance = 0;
for (final tx in transactions!.entries) { for (final tx in transactions!.entries) {
if (tx.value.direction == TransactionDirection.incoming) { if (tx.value.direction == TransactionDirection.incoming) {

View file

@ -9,20 +9,6 @@ abstract class CryptonoteWallet<T extends CryptonoteCurrency> extends Wallet<T>
with MnemonicInterface<T> { with MnemonicInterface<T> {
CryptonoteWallet(super.currency); CryptonoteWallet(super.currency);
Completer<void>? walletOpenCompleter;
void resetWalletOpenCompleter() {
if (walletOpenCompleter == null || walletOpenCompleter!.isCompleted) {
walletOpenCompleter = Completer<void>();
}
}
Future<void> waitForWalletOpen() async {
if (walletOpenCompleter != null && !walletOpenCompleter!.isCompleted) {
await walletOpenCompleter!.future;
}
}
// ========== Overrides ====================================================== // ========== Overrides ======================================================
@override @override

View file

@ -29,7 +29,8 @@ import '../../isar/models/wallet_info.dart';
import '../intermediate/cryptonote_wallet.dart'; import '../intermediate/cryptonote_wallet.dart';
import 'multi_address_interface.dart'; import 'multi_address_interface.dart';
mixin CwBasedInterface<T extends CryptonoteCurrency> on CryptonoteWallet<T> mixin CwBasedInterface<T extends CryptonoteCurrency, U extends WalletBase,
V extends WalletService> on CryptonoteWallet<T>
implements MultiAddressInterface<T> { implements MultiAddressInterface<T> {
final prepareSendMutex = Mutex(); final prepareSendMutex = Mutex();
final estimateFeeMutex = Mutex(); final estimateFeeMutex = Mutex();
@ -38,10 +39,6 @@ mixin CwBasedInterface<T extends CryptonoteCurrency> on CryptonoteWallet<T>
KeyService get cwKeysStorage => KeyService get cwKeysStorage =>
_cwKeysStorageCached ??= KeyService(secureStorageInterface); _cwKeysStorageCached ??= KeyService(secureStorageInterface);
static WalletService? cwWalletService;
static WalletBase? cwWalletBase;
bool _hasCalledExit = false;
bool _txRefreshLock = false; bool _txRefreshLock = false;
int _lastCheckedHeight = -1; int _lastCheckedHeight = -1;
int _txCount = 0; int _txCount = 0;
@ -94,6 +91,7 @@ mixin CwBasedInterface<T extends CryptonoteCurrency> on CryptonoteWallet<T>
void syncStatusChanged() async { void syncStatusChanged() async {
final syncStatus = cwWalletBase?.syncStatus; final syncStatus = cwWalletBase?.syncStatus;
if (syncStatus != null) { if (syncStatus != null) {
if (syncStatus.progress() == 1 && refreshMutex.isLocked) { if (syncStatus.progress() == 1 && refreshMutex.isLocked) {
refreshMutex.release(); refreshMutex.release();
@ -188,11 +186,12 @@ mixin CwBasedInterface<T extends CryptonoteCurrency> on CryptonoteWallet<T>
// ============ Interface ==================================================== // ============ Interface ====================================================
U? get cwWalletBase;
V? get cwWalletService;
Future<Amount> get availableBalance; Future<Amount> get availableBalance;
Future<Amount> get totalBalance; Future<Amount> get totalBalance;
Future<void> exitCwWallet();
Future<void> open(); Future<void> open();
Address addressFor({required int index, int account = 0}); Address addressFor({required int index, int account = 0});
@ -303,20 +302,11 @@ mixin CwBasedInterface<T extends CryptonoteCurrency> on CryptonoteWallet<T>
} }
} }
static Mutex exitMutex = Mutex();
@override @override
Future<void> exit() async { Future<void> exit() async {
if (!_hasCalledExit) { autoSaveTimer?.cancel();
await exitMutex.protect(() async { await cwWalletBase?.save();
_hasCalledExit = true; cwWalletBase?.close();
autoSaveTimer?.cancel();
await exitCwWallet();
cwWalletBase?.close();
cwWalletBase = null;
cwWalletService = null;
});
}
} }
@override @override