From 9ea0caea64b787b8b73787514f72f3d1b9f72713 Mon Sep 17 00:00:00 2001 From: Blazebrain Date: Tue, 13 Jun 2023 10:03:17 +0100 Subject: [PATCH] Restore wallet WIP --- .gitignore | 1 + cw_monero/lib/api/transaction_history.dart | 51 ++++---- cw_monero/lib/monero_wallet.dart | 122 +++++++++---------- lib/view_model/wallet_creation_vm.dart | 132 +++++++++++++-------- 4 files changed, 173 insertions(+), 133 deletions(-) diff --git a/.gitignore b/.gitignore index 9fb7fd204..70d99f753 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ .buildlog/ .history .svn/ +.fvm/ # IntelliJ related *.iml diff --git a/cw_monero/lib/api/transaction_history.dart b/cw_monero/lib/api/transaction_history.dart index 0fc507500..46573adc7 100644 --- a/cw_monero/lib/api/transaction_history.dart +++ b/cw_monero/lib/api/transaction_history.dart @@ -28,7 +28,8 @@ final transactionCreateNative = moneroApi .asFunction(); final transactionCreateMultDestNative = moneroApi - .lookup>('transaction_create_mult_dest') + .lookup>( + 'transaction_create_mult_dest') .asFunction(); final transactionCommitNative = moneroApi @@ -97,6 +98,7 @@ PendingTransactionDescription createTransactionSync( if (!created) { final message = errorMessagePointer.ref.getValue(); calloc.free(errorMessagePointer); + print('Error message from creating transaction call $message'); throw CreationTransactionException(message: message); } @@ -111,15 +113,15 @@ PendingTransactionDescription createTransactionSync( PendingTransactionDescription createTransactionMultDestSync( {required List outputs, - required String paymentId, - required int priorityRaw, - int accountIndex = 0}) { + required String paymentId, + required int priorityRaw, + int accountIndex = 0}) { final int size = outputs.length; - final List> addressesPointers = outputs.map((output) => - output.address.toNativeUtf8()).toList(); + final List> addressesPointers = + outputs.map((output) => output.address.toNativeUtf8()).toList(); final Pointer> addressesPointerPointer = calloc(size); - final List> amountsPointers = outputs.map((output) => - output.amount.toNativeUtf8()).toList(); + final List> amountsPointers = + outputs.map((output) => output.amount.toNativeUtf8()).toList(); final Pointer> amountsPointerPointer = calloc(size); for (int i = 0; i < size; i++) { @@ -131,14 +133,14 @@ PendingTransactionDescription createTransactionMultDestSync( final errorMessagePointer = calloc(); final pendingTransactionRawPointer = calloc(); final created = transactionCreateMultDestNative( - addressesPointerPointer, - paymentIdPointer, - amountsPointerPointer, - size, - priorityRaw, - accountIndex, - errorMessagePointer, - pendingTransactionRawPointer) != + addressesPointerPointer, + paymentIdPointer, + amountsPointerPointer, + size, + priorityRaw, + accountIndex, + errorMessagePointer, + pendingTransactionRawPointer) != 0; calloc.free(addressesPointerPointer); @@ -164,10 +166,13 @@ PendingTransactionDescription createTransactionMultDestSync( pointerAddress: pendingTransactionRawPointer.address); } -void commitTransactionFromPointerAddress({required int address}) => commitTransaction( - transactionPointer: Pointer.fromAddress(address)); +void commitTransactionFromPointerAddress({required int address}) => + commitTransaction( + transactionPointer: + Pointer.fromAddress(address)); -void commitTransaction({required Pointer transactionPointer}) { +void commitTransaction( + {required Pointer transactionPointer}) { final errorMessagePointer = calloc(); final isCommited = transactionCommitNative(transactionPointer, errorMessagePointer) != 0; @@ -222,10 +227,10 @@ Future createTransaction( }); Future createTransactionMultDest( - {required List outputs, - required int priorityRaw, - String paymentId = '', - int accountIndex = 0}) => + {required List outputs, + required int priorityRaw, + String paymentId = '', + int accountIndex = 0}) => compute(_createTransactionMultDestSync, { 'outputs': outputs, 'paymentId': paymentId, diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index e6d9dd033..eceb30654 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -38,29 +38,29 @@ abstract class MoneroWalletBase extends WalletBase with Store { MoneroWalletBase({required WalletInfo walletInfo}) : balance = ObservableMap.of({ - CryptoCurrency.xmr: MoneroBalance( + CryptoCurrency.xmr: MoneroBalance( fullBalance: monero_wallet.getFullBalance(accountIndex: 0), unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0)) - }), + }), _isTransactionUpdating = false, _hasSyncAfterStartup = false, walletAddresses = MoneroWalletAddresses(walletInfo), syncStatus = NotConnectedSyncStatus(), super(walletInfo) { transactionHistory = MoneroTransactionHistory(); - _onAccountChangeReaction = reaction((_) => walletAddresses.account, - (Account? account) { + _onAccountChangeReaction = + reaction((_) => walletAddresses.account, (Account? account) { if (account == null) { return; } - balance = ObservableMap.of( - { - currency: MoneroBalance( + balance = ObservableMap.of({ + currency: MoneroBalance( fullBalance: monero_wallet.getFullBalance(accountIndex: account.id), unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id)) - }); + }); walletAddresses.updateSubaddressList(accountIndex: account.id); }); } @@ -96,12 +96,14 @@ abstract class MoneroWalletBase extends WalletBase init() async { await walletAddresses.init(); - balance = ObservableMap.of( - { - currency: MoneroBalance( - fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id), - unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id)) - }); + balance = ObservableMap.of({ + currency: MoneroBalance( + fullBalance: monero_wallet.getFullBalance( + accountIndex: walletAddresses.account!.id), + unlockedBalance: monero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id)) + }); _setListeners(); await updateTransactions(); @@ -115,9 +117,9 @@ abstract class MoneroWalletBase extends WalletBase await save()); + Duration(seconds: _autoSaveInterval), (_) async => await save()); } + @override Future? updateBalance() => null; @@ -170,69 +172,68 @@ abstract class MoneroWalletBase extends WalletBase 1; - final unlockedBalance = - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id); + final unlockedBalance = monero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id); PendingTransactionDescription pendingTransactionDescription; // if (!(syncStatus is SyncedSyncStatus)) { + // print('Wallet is not synced'); // throw MoneroTransactionCreationException('The wallet is not synced.'); // } if (hasMultiDestination) { - if (outputs.any((item) => item.sendAll - || (item.formattedCryptoAmount ?? 0) <= 0)) { - throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.'); + if (outputs.any( + (item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { + throw MoneroTransactionCreationException( + 'You do not have enough XMR to send this amount.'); } - final int totalAmount = outputs.fold(0, (acc, value) => - acc + (value.formattedCryptoAmount ?? 0)); + final int totalAmount = outputs.fold( + 0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); if (unlockedBalance < totalAmount) { - throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.'); + throw MoneroTransactionCreationException( + 'You do not have enough XMR to send this amount.'); } final moneroOutputs = outputs.map((output) { - final outputAddress = output.isParsedAddress - ? output.extractedAddress - : output.address; + final outputAddress = + output.isParsedAddress ? output.extractedAddress : output.address; - return MoneroOutput( - address: outputAddress!, - amount: output.cryptoAmount!.replaceAll(',', '.')); + return MoneroOutput( + address: outputAddress!, + amount: output.cryptoAmount!.replaceAll(',', '.')); }).toList(); pendingTransactionDescription = - await transaction_history.createTransactionMultDest( - outputs: moneroOutputs, - priorityRaw: _credentials.priority.serialize(), - accountIndex: walletAddresses.account!.id); + await transaction_history.createTransactionMultDest( + outputs: moneroOutputs, + priorityRaw: _credentials.priority.serialize(), + accountIndex: walletAddresses.account!.id); } else { final output = outputs.first; - final address = output.isParsedAddress - ? output.extractedAddress - : output.address; - final amount = output.sendAll - ? null - : output.cryptoAmount!.replaceAll(',', '.'); - final formattedAmount = output.sendAll - ? null - : output.formattedCryptoAmount; + final address = + output.isParsedAddress ? output.extractedAddress : output.address; + final amount = + output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); + final formattedAmount = + output.sendAll ? null : output.formattedCryptoAmount; - if ((formattedAmount != null && unlockedBalance < formattedAmount) || - (formattedAmount == null && unlockedBalance <= 0)) { - final formattedBalance = moneroAmountToString(amount: unlockedBalance); + // if ((formattedAmount != null && unlockedBalance < formattedAmount) || + // (formattedAmount == null && unlockedBalance <= 0)) { + // final formattedBalance = moneroAmountToString(amount: unlockedBalance); - throw MoneroTransactionCreationException( - 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); - } + // throw MoneroTransactionCreationException( + // 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); + // } pendingTransactionDescription = - await transaction_history.createTransaction( - address: address!, - amount: amount, - priorityRaw: _credentials.priority.serialize(), - accountIndex: walletAddresses.account!.id); + await transaction_history.createTransaction( + address: address!, + amount: amount, + priorityRaw: _credentials.priority.serialize(), + accountIndex: walletAddresses.account!.id); } return PendingMoneroTransaction(pendingTransactionDescription); @@ -297,8 +298,7 @@ abstract class MoneroWalletBase extends WalletBase monero_wallet.getAddress( - accountIndex: accountIndex, - addressIndex: addressIndex); + accountIndex: accountIndex, addressIndex: addressIndex); @override Future> fetchTransactions() async { @@ -394,8 +394,8 @@ abstract class MoneroWalletBase extends WalletBase monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id); - int _getUnlockedBalance() => - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id); + int _getUnlockedBalance() => monero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id); void _onNewBlock(int height, int blocksLeft, double ptc) async { try { @@ -412,9 +412,9 @@ abstract class MoneroWalletBase extends WalletBase _walletInfoSource; final AppStore _appStore; - final FiatConversionStore _fiatConversationStore; + final FiatConversionStore _fiatConversationStore; - Completer syncCompleter = Completer(); + Completer syncCompleter = Completer(); bool nameExists(String name) => walletCreationService.exists(name); @@ -58,13 +60,16 @@ abstract class WalletCreationVMBase with Store { final type = restoreWallet?.type ?? this.type; try { //! Create a restoredWallet from the scanned wallet parameters - final restoredWallet = - await createNewWalletWithoutSwitching(options: options, restoreWallet: restoreWallet); - print('Restored Wallet Address ' + restoredWallet.walletAddresses.address); + final restoredWallet = await createNewWalletWithoutSwitching( + options: options, restoreWallet: restoreWallet); + print( + 'Restored Wallet Address ' + restoredWallet.walletAddresses.address); //TODO Get transactions details to verify 10 confirmations - //! Create the newWallet that will received the funds + // if (restoreWallet != null && + // restoreWallet.restoreMode == WalletRestoreMode.txids) { + //* Create the newWallet that will received the funds final newWallet = await createNewWalletWithoutSwitching( options: options, regenerateName: true, @@ -72,31 +77,36 @@ abstract class WalletCreationVMBase with Store { final newWalletAddress = newWallet.walletAddresses.address; print('New Wallet Address ' + newWalletAddress); - //! Switch to the restoredWallet in order to activate the node connection + //* Switch to the restoredWallet in order to activate the node connection _appStore.changeCurrentWallet(restoredWallet); await restoredWallet.startSync(); - - //! Sweep all funds from restoredWallet to newWallet - await sweepAllFundsToNewWallet(restoredWallet, type, newWalletAddress, restoreWallet?.txId ?? ''); - //! Switch back to new wallet - _appStore.changeCurrentWallet(newWallet); - - //! Add the new Wallet info to the walletInfoSource - await _walletInfoSource.add(newWallet.walletInfo); - - //! Approve authentication as successful - _appStore.authenticationStore.allowed(); - state = ExecutedSuccessfullyState(); + //* Sweep all funds from restoredWallet to newWallet + await sweepAllFundsToNewWallet( + restoredWallet, + type, + newWalletAddress, + restoreWallet?.txId ?? '', + ); + // } else { + // await _walletInfoSource.add(restoredWallet.walletInfo); + // _appStore.changeCurrentWallet(restoredWallet); + // _appStore.authenticationStore.allowed(); + // state = ExecutedSuccessfullyState(); + // } } catch (e) { + print('Errorrrrr'); state = FailureState(e.toString()); } } - Future, TransactionInfo>> - createNewWalletWithoutSwitching( - {dynamic options, RestoredWallet? restoreWallet, bool regenerateName = false}) async { + Future< + WalletBase, + TransactionInfo>> createNewWalletWithoutSwitching( + {dynamic options, + RestoredWallet? restoreWallet, + bool regenerateName = false}) async { state = IsExecutingState(); if (name.isEmpty) { name = await generateName(); @@ -122,35 +132,55 @@ abstract class WalletCreationVMBase with Store { path: path, dirPath: dirPath, address: '', - showIntroCakePayCard: - (!walletCreationService.typeExists(type)) && type != WalletType.haven); + showIntroCakePayCard: (!walletCreationService.typeExists(type)) && + type != WalletType.haven); credentials.walletInfo = walletInfo; final wallet = restoreWallet != null ? await processFromRestoredWallet(credentials, restoreWallet) : await process(credentials); walletInfo.address = wallet.walletAddresses.address; - - + return wallet; } - Future sweepAllFundsToNewWallet(WalletBase, TransactionInfo> wallet, - WalletType type, String newWalletAddress, String paymentId) async { - final output = Output(wallet, _appStore.settingsStore, _fiatConversationStore, () => wallet.currency); - output.address = newWalletAddress; - output.sendAll = true; - output.note = 'testing the sweep all function'; - final credentials = _credentials(type, wallet.currency.title, output); - print('About to enter create function'); - await createTransaction(wallet, credentials); - // final currentNode = _appStore.settingsStore.getCurrentNode(type); + Future sweepAllFundsToNewWallet( + WalletBase, + TransactionInfo> + wallet, + WalletType type, + String newWalletAddress, + String paymentId) async { + final output = Output(wallet, _appStore.settingsStore, + _fiatConversationStore, () => wallet.currency); + output.address = newWalletAddress; + output.sendAll = true; + output.note = 'testing the sweep all function'; + final credentials = _credentials(type, wallet.currency.title, output); + print('About to enter create function'); + try { + await createTransaction(wallet, credentials); + // final currentNode = _appStore.settingsStore.getCurrentNode(type); // final result = await walletCreationService.sweepAllFunds(currentNode, newWalletAddress, paymentId); + + //* Switch back to new wallet + _appStore.changeCurrentWallet(wallet); + + //* Add the new Wallet info to the walletInfoSource + await _walletInfoSource.add(wallet.walletInfo); + + //* Approve authentication as successful + _appStore.authenticationStore.allowed(); + print('Successfully done inisde sweep all'); + state = ExecutedSuccessfullyState(); + } catch (e) { + state = FailureState(e.toString()); + } } - - Object _credentials(WalletType type,String cryptoCurrencyTitle,Output output ) { + Object _credentials( + WalletType type, String cryptoCurrencyTitle, Output output) { switch (type) { case WalletType.bitcoin: final priority = _appStore.settingsStore.priority[type]; @@ -159,7 +189,8 @@ abstract class WalletCreationVMBase with Store { throw Exception('Priority is null for wallet type: ${type}'); } - return bitcoin!.createBitcoinTransactionCredentials([output], priority: priority); + return bitcoin! + .createBitcoinTransactionCredentials([output], priority: priority); case WalletType.litecoin: final priority = _appStore.settingsStore.priority[type]; @@ -167,7 +198,8 @@ abstract class WalletCreationVMBase with Store { throw Exception('Priority is null for wallet type: ${type}'); } - return bitcoin!.createBitcoinTransactionCredentials([output], priority: priority); + return bitcoin! + .createBitcoinTransactionCredentials([output], priority: priority); case WalletType.monero: final priority = _appStore.settingsStore.priority[type]; @@ -176,16 +208,18 @@ abstract class WalletCreationVMBase with Store { } return monero!.createMoneroTransactionCreationCredentials( - outputs:[output], priority: priority); + outputs: [output], priority: priority); case WalletType.haven: final priority = _appStore.settingsStore.priority[type]; if (priority == null) { throw Exception('Priority is null for wallet type: ${type}'); } - + return haven!.createHavenTransactionCreationCredentials( - outputs: [output], priority: priority, assetType: cryptoCurrencyTitle); + outputs: [output], + priority: priority, + assetType: cryptoCurrencyTitle); default: throw Exception('Unexpected wallet type: ${type}'); } @@ -194,7 +228,7 @@ abstract class WalletCreationVMBase with Store { @action Future createTransaction(WalletBase wallet, Object credentials) async { try { - print('in here'); + print('in here'); state = IsExecutingState(); print('about to enter wallet create transaction function'); pendingTransaction = await wallet.createTransaction(credentials); @@ -207,15 +241,15 @@ abstract class WalletCreationVMBase with Store { WalletCredentials getCredentials(dynamic options) { switch (type) { case WalletType.monero: - return monero! - .createMoneroNewWalletCredentials(name: name, language: options as String? ?? ''); + return monero!.createMoneroNewWalletCredentials( + name: name, language: options as String? ?? ''); case WalletType.bitcoin: return bitcoin!.createBitcoinNewWalletCredentials(name: name); case WalletType.litecoin: return bitcoin!.createBitcoinNewWalletCredentials(name: name); case WalletType.haven: - return haven! - .createHavenNewWalletCredentials(name: name, language: options as String? ?? ''); + return haven!.createHavenNewWalletCredentials( + name: name, language: options as String? ?? ''); default: throw Exception('Unexpected type: ${type.toString()}'); }