feat: Implement sweep all WIP [skip ci]

This commit is contained in:
Blazebrain 2023-07-11 09:00:33 +01:00
parent 9f4e6f1a3a
commit ef335efc5b
15 changed files with 294 additions and 271 deletions

View file

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
@ -348,6 +349,12 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
}); });
} }
@override
Future<PendingTransaction> createTransactionForSweepAll(Object credentials) {
// TODO: implement createTransactionForSweepAllElectrum
throw UnimplementedError();
}
String toJSON() => json.encode({ String toJSON() => json.encode({
'mnemonic': mnemonic, 'mnemonic': mnemonic,
'account_index': walletAddresses.currentReceiveAddressIndex.toString(), 'account_index': walletAddresses.currentReceiveAddressIndex.toString(),

View file

@ -56,6 +56,8 @@ abstract class WalletBase<
Future<PendingTransaction> createTransaction(Object credentials); Future<PendingTransaction> createTransaction(Object credentials);
Future<PendingTransaction> createTransactionForSweepAll(Object credentials);
int calculateEstimatedFee(TransactionPriority priority, int? amount); int calculateEstimatedFee(TransactionPriority priority, int? amount);
// void fetchTransactionsAsync( // void fetchTransactionsAsync(

View file

@ -2,8 +2,6 @@ import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'node.dart';
abstract class WalletService<N extends WalletCredentials, abstract class WalletService<N extends WalletCredentials,
RFS extends WalletCredentials, RFS extends WalletCredentials,
RFK extends WalletCredentials> { RFK extends WalletCredentials> {
@ -15,8 +13,6 @@ abstract class WalletService<N extends WalletCredentials,
Future<WalletBase> restoreFromKeys(RFK credentials); Future<WalletBase> restoreFromKeys(RFK credentials);
Future<Map<String, dynamic>> sweepAllFunds(Node node, String address, String paymentId);
Future<WalletBase> openWallet(String name, String password); Future<WalletBase> openWallet(String name, String password);
Future<bool> isWalletExit(String name); Future<bool> isWalletExit(String name);

View file

@ -222,6 +222,12 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
return PendingHavenTransaction(pendingTransactionDescription, assetType); return PendingHavenTransaction(pendingTransactionDescription, assetType);
} }
@override
Future<PendingTransaction> createTransactionForSweepAll(Object credentials) {
// TODO: implement createTransactionForSweepAllHaven
throw UnimplementedError();
}
@override @override
int calculateEstimatedFee(TransactionPriority priority, int? amount) { int calculateEstimatedFee(TransactionPriority priority, int? amount) {
// FIXME: hardcoded value; // FIXME: hardcoded value;

View file

@ -172,8 +172,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
final _credentials = credentials as MoneroTransactionCreationCredentials; final _credentials = credentials as MoneroTransactionCreationCredentials;
final outputs = _credentials.outputs; final outputs = _credentials.outputs;
final hasMultiDestination = outputs.length > 1; final hasMultiDestination = outputs.length > 1;
// final unlockedBalance = monero_wallet.getUnlockedBalance(
// accountIndex: walletAddresses.accountList.accounts.first.id); final unlockedBalance = monero_wallet.getUnlockedBalance(
accountIndex: walletAddresses.account!.id);
PendingTransactionDescription pendingTransactionDescription; PendingTransactionDescription pendingTransactionDescription;
@ -192,10 +193,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
final int totalAmount = outputs.fold( final int totalAmount = outputs.fold(
0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); 0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
// if (unlockedBalance < totalAmount) { if (unlockedBalance < totalAmount) {
// throw MoneroTransactionCreationException( throw MoneroTransactionCreationException(
// 'You do not have enough XMR to send this amount.'); 'You do not have enough XMR to send this amount.');
// } }
final moneroOutputs = outputs.map((output) { final moneroOutputs = outputs.map((output) {
final outputAddress = final outputAddress =
@ -217,16 +218,17 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
output.isParsedAddress ? output.extractedAddress : output.address; output.isParsedAddress ? output.extractedAddress : output.address;
final amount = final amount =
output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
// final formattedAmount =
// output.sendAll ? null : output.formattedCryptoAmount;
// if ((formattedAmount != null && unlockedBalance < formattedAmount) || final formattedAmount =
// (formattedAmount == null && unlockedBalance <= 0)) { output.sendAll ? null : output.formattedCryptoAmount;
// final formattedBalance = moneroAmountToString(amount: unlockedBalance);
// throw MoneroTransactionCreationException( if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
// 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); (formattedAmount == null && unlockedBalance <= 0)) {
// } final formattedBalance = moneroAmountToString(amount: unlockedBalance);
throw MoneroTransactionCreationException(
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
}
pendingTransactionDescription = pendingTransactionDescription =
await transaction_history.createTransaction( await transaction_history.createTransaction(
@ -239,6 +241,34 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
return PendingMoneroTransaction(pendingTransactionDescription); return PendingMoneroTransaction(pendingTransactionDescription);
} }
@override
Future<PendingTransaction> createTransactionForSweepAll(
Object credentials) async {
final _credentials = credentials as MoneroTransactionCreationCredentials;
final outputs = _credentials.outputs;
PendingTransactionDescription pendingTransactionDescription;
if (!(syncStatus is SyncedSyncStatus)) {
print('Wallet is not synced');
throw MoneroTransactionCreationException('The wallet is not synced.');
}
final output = outputs.first;
final address =
output.isParsedAddress ? output.extractedAddress : output.address;
final amount =
output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
pendingTransactionDescription = await transaction_history.createTransaction(
address: address!,
amount: amount,
priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account!.id);
return PendingMoneroTransaction(pendingTransactionDescription);
}
@override @override
int calculateEstimatedFee(TransactionPriority priority, int? amount) { int calculateEstimatedFee(TransactionPriority priority, int? amount) {
// FIXME: hardcoded value; // FIXME: hardcoded value;
@ -423,7 +453,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
walletAddresses.accountList.update(); walletAddresses.accountList.update();
syncStatus = SyncedSyncStatus(); syncStatus = SyncedSyncStatus();
//! Introduce completer //! Introduce completer
if (!syncCompleter.isCompleted) {
syncCompleter.complete(); syncCompleter.complete();
}
if (!_hasSyncAfterStartup) { if (!_hasSyncAfterStartup) {
_hasSyncAfterStartup = true; _hasSyncAfterStartup = true;
await save(); await save();

View file

@ -1,10 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'package:cw_core/node.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_core/monero_wallet_utils.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager; import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
import 'package:cw_monero/monero_wallet.dart'; import 'package:cw_monero/monero_wallet.dart';
import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_credentials.dart';
@ -185,28 +183,6 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
} }
} }
@override
Future<Map<String, dynamic>> sweepAllFunds(Node node, String address, String paymentId) async {
try {
final response = await monero_wallet_manager.sweepFundsToNewWallet(
node: node,
address: address,
paymentId: paymentId,
);
if (response['error'] != null) {
throw Exception('${response['error']['message']}');
} else {
return response;
}
} catch (e) {
// TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e');
rethrow;
}
}
Future<void> repairOldAndroidWallet(String name) async { Future<void> repairOldAndroidWallet(String name) async {
try { try {
if (!Platform.isAndroid) { if (!Platform.isAndroid) {

View file

@ -1,8 +1,6 @@
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -97,9 +95,4 @@ class WalletCreationService {
return wallet; return wallet;
} }
Future<Map<String, dynamic>> sweepAllFunds(Node node, String address, String paymentId) async {
final result = await _service!.sweepAllFunds(node, address, paymentId);
return result;
}
} }

View file

@ -301,7 +301,12 @@ Future setup({
(WalletType type) => getIt.get<WalletService>(param1: type))); (WalletType type) => getIt.get<WalletService>(param1: type)));
getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) => WalletNewVM( getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) => WalletNewVM(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type),getIt.get<FiatConversionStore>(), _walletInfoSource, getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
getIt.get<FiatConversionStore>(),
transactionDescriptionBox,
_walletInfoSource,
type: type)); type: type));
getIt.registerFactoryParam<WalletRestorationFromSeedVM, List, void>((args, _) { getIt.registerFactoryParam<WalletRestorationFromSeedVM, List, void>((args, _) {
@ -310,7 +315,11 @@ Future setup({
final mnemonic = args[2] as String; final mnemonic = args[2] as String;
return WalletRestorationFromSeedVM( return WalletRestorationFromSeedVM(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource , getIt.get<FiatConversionStore>(), getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
_walletInfoSource,
getIt.get<FiatConversionStore>(),
transactionDescriptionBox,
type: type, language: language, seed: mnemonic); type: type, language: language, seed: mnemonic);
}); });
@ -319,13 +328,21 @@ Future setup({
final language = args[1] as String; final language = args[1] as String;
return WalletRestorationFromKeysVM( return WalletRestorationFromKeysVM(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource, getIt.get<FiatConversionStore>(), getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
_walletInfoSource,
getIt.get<FiatConversionStore>(),
transactionDescriptionBox,
type: type, language: language); type: type, language: language);
}); });
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) { getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
return WalletRestorationFromQRVM(getIt.get<AppStore>(), return WalletRestorationFromQRVM(getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type), getIt.get<FiatConversionStore>(), _walletInfoSource, type); getIt.get<WalletCreationService>(param1: type),
getIt.get<FiatConversionStore>(),
transactionDescriptionBox,
_walletInfoSource,
type);
}); });
getIt.registerFactory<WalletAddressListViewModel>(() => WalletAddressListViewModel( getIt.registerFactory<WalletAddressListViewModel>(() => WalletAddressListViewModel(
@ -742,7 +759,11 @@ Future setup({
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) => getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) =>
WalletRestoreViewModel( WalletRestoreViewModel(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type),getIt.get<FiatConversionStore>(), _walletInfoSource, getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
getIt.get<FiatConversionStore>(),
transactionDescriptionBox,
_walletInfoSource,
type: type)); type: type));
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>( getIt.registerFactoryParam<WalletRestorePage, WalletType, void>(

View file

@ -65,19 +65,20 @@ class RestoreOptionsPage extends BasePage {
} }
if (!isNewInstall || isPinSet) { if (!isNewInstall || isPinSet) {
try { try {
//! This gives us the restored wallet
final restoreWallet = final restoreWallet =
await WalletRestoreFromQRCode.scanQRCodeForRestoring(context); await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);
//! Next step will be to create a new wallet from this
final restoreFromQRViewModel = final restoreFromQRViewModel =
getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type); getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type);
await restoreFromQRViewModel.create(restoreWallet: restoreWallet); await restoreFromQRViewModel.create(restoreWallet: restoreWallet);
if (restoreFromQRViewModel.state is FailureState) { if (restoreFromQRViewModel.state is FailureState) {
final errorState = restoreFromQRViewModel.state as FailureState; final errorState = restoreFromQRViewModel.state as FailureState;
_onWalletCreateFailure(context, _onWalletCreateFailure(context,
'Create wallet state: ${errorState.error}'); 'Create wallet state: ${errorState.error}');
} }
} catch (e) { } catch (e) {
_onWalletCreateFailure(context, e.toString()); _onWalletCreateFailure(context, e.toString());
} }

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.dart'; import 'package:cake_wallet/view_model/restore/restore_mode.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
@ -19,14 +20,20 @@ part 'restore_from_qr_vm.g.dart';
class WalletRestorationFromQRVM = WalletRestorationFromQRVMBase with _$WalletRestorationFromQRVM; class WalletRestorationFromQRVM = WalletRestorationFromQRVMBase with _$WalletRestorationFromQRVM;
abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store { abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store {
WalletRestorationFromQRVMBase(AppStore appStore, WalletCreationService walletCreationService,FiatConversionStore fiatConversationStore, WalletRestorationFromQRVMBase(
AppStore appStore,
WalletCreationService walletCreationService,
FiatConversionStore fiatConversationStore,
Box<TransactionDescription> transactionDescriptionBox,
Box<WalletInfo> walletInfoSource, WalletType type) Box<WalletInfo> walletInfoSource, WalletType type)
: height = 0, : height = 0,
viewKey = '', viewKey = '',
spendKey = '', spendKey = '',
wif = '', wif = '',
address = '', address = '',
super(appStore, walletInfoSource, walletCreationService, fiatConversationStore, type: type, isRecovery: true); super(appStore, walletInfoSource, walletCreationService,
fiatConversationStore, transactionDescriptionBox,
type: type, isRecovery: true);
@observable @observable
int height; int height;
@ -78,6 +85,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
height: restoreWallet.height ?? 0, height: restoreWallet.height ?? 0,
mnemonic: restoreWallet.mnemonicSeed ?? '', mnemonic: restoreWallet.mnemonicSeed ?? '',
password: password); password: password);
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.litecoin: case WalletType.litecoin:
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(

View file

@ -1,8 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'package:cake_wallet/core/wallet_creation_service.dart'; import 'package:cake_wallet/core/wallet_creation_service.dart';
import 'package:cake_wallet/entities/load_current_wallet.dart'; import 'package:cake_wallet/entities/load_current_wallet.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.dart'; import 'package:cake_wallet/view_model/restore/restore_mode.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
@ -31,10 +31,16 @@ part 'wallet_creation_vm.g.dart';
class WalletCreationVM = WalletCreationVMBase with _$WalletCreationVM; class WalletCreationVM = WalletCreationVMBase with _$WalletCreationVM;
abstract class WalletCreationVMBase with Store { abstract class WalletCreationVMBase with Store {
WalletCreationVMBase(this._appStore, this._walletInfoSource, WalletCreationVMBase(
this.walletCreationService, this._fiatConversationStore, this._appStore,
{required this.type, required this.isRecovery}) this._walletInfoSource,
this.walletCreationService,
this._fiatConversationStore,
this.transactionDescriptionBox,
{required this.type,
required this.isRecovery})
: state = InitialExecutionState(), : state = InitialExecutionState(),
outputs = ObservableList(),
name = ''; name = '';
@observable @observable
@ -46,70 +52,117 @@ abstract class WalletCreationVMBase with Store {
@observable @observable
PendingTransaction? pendingTransaction; PendingTransaction? pendingTransaction;
@observable
ObservableList<Output> outputs;
WalletType type; WalletType type;
final bool isRecovery; final bool isRecovery;
final WalletCreationService walletCreationService; final WalletCreationService walletCreationService;
final Box<WalletInfo> _walletInfoSource; final Box<WalletInfo> _walletInfoSource;
final AppStore _appStore; final AppStore _appStore;
final FiatConversionStore _fiatConversationStore; final FiatConversionStore _fiatConversationStore;
final Box<TransactionDescription> transactionDescriptionBox;
bool nameExists(String name) => walletCreationService.exists(name); bool nameExists(String name) => walletCreationService.exists(name);
bool typeExists(WalletType type) => walletCreationService.typeExists(type); bool typeExists(WalletType type) => walletCreationService.typeExists(type);
Future<void> create({dynamic options, RestoredWallet? restoreWallet}) async { Future<void> create({dynamic options, RestoredWallet? restoreWallet}) async {
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);
//TODO Get transactions details to verify 10 confirmations
// if (restoreWallet != null && // if (restoreWallet != null &&
// restoreWallet.restoreMode == WalletRestoreMode.txids) { // restoreWallet.restoreMode == WalletRestoreMode.txids) {
await _createFlowForSweepAll(options, restoreWallet);
// }
//* Switch to the restoredWallet in order to activate the node connection // await _createTransactionFlowNormally(options, restoreWallet);
await _walletInfoSource.add(restoredWallet.walletInfo); }
await connectToNode(restoredWallet);
_appStore.changeCurrentWallet(restoredWallet);
await loadCurrentWallet();
await restoredWallet.startSync();
print('Before syncing starts');
await syncCompleter.future;
print('After syncing ends');
// * Create the newWallet that will receive the funds Future<void> _createTransactionFlowNormally(
final newWallet = await createNewWalletWithoutSwitching( dynamic options,
RestoredWallet? restoreWallet,
) async {
try {
final restoredWallet = await _createNewWalletWithoutSwitching(
options: options, options: options,
restoreWallet: restoreWallet,
regenerateName: true, regenerateName: true,
); );
final newWalletAddress = newWallet.walletAddresses.address;
print('New Wallet Address ' + newWalletAddress);
// * Sweep all funds from restoredWallet to newWallet print(
await sweepAllFundsToNewWallet( 'Restored Wallet Address ' + restoredWallet.walletAddresses.address,
restoredWallet,
newWallet,
type,
newWalletAddress,
restoreWallet?.txId ?? '',
); );
// } else {
// await _walletInfoSource.add(restoredWallet.walletInfo); await _walletInfoSource.add(restoredWallet.walletInfo);
// _appStore.changeCurrentWallet(restoredWallet);
_appStore.changeCurrentWallet(restoredWallet);
_appStore.authenticationStore.allowed(); _appStore.authenticationStore.allowed();
state = ExecutedSuccessfullyState(); state = ExecutedSuccessfullyState();
// }
} catch (e) { } catch (e) {
print('Errorrrrr'); print('Error occurred while creating a new wallet from Scan QR normally');
state = FailureState(e.toString()); state = FailureState(e.toString());
} }
} }
Future<void> connectToNode( Future<void> _createFlowForSweepAll(
dynamic options,
RestoredWallet? restoreWallet,
) async {
final type = restoreWallet?.type ?? this.type;
try {
final newWallet =
await _createNewWalletWithoutSwitching(options: options);
final newWalletAddress = newWallet.walletAddresses.address;
print('New Wallet Address ' + newWalletAddress);
final restoredWallet = await _createNewWalletWithoutSwitching(
options: options,
restoreWallet: restoreWallet,
regenerateName: true,
);
print(
'Restored Wallet Address ' + restoredWallet.walletAddresses.address,
);
//* Switch to the restoredWallet in order to activate the node connection
await _walletInfoSource.add(restoredWallet.walletInfo);
//* Connect to Node to get the ConnectedSyncStatus
await _connectToNode(restoredWallet);
//* Switch to the restoredWallet for good measure
_appStore.changeCurrentWallet(restoredWallet);
//* Load the wallet to simulate a real wallet interaction environment
await loadCurrentWallet();
//*Synchronize
await restoredWallet.startSync();
await syncCompleter.future;
// * Sweep all funds from restoredWallet to newWallet
await _sweepAllFundsToNewWallet(
restoredWallet,
newWallet,
type,
restoreWallet?.txId ?? '',
);
} catch (e) {
print(
'Error occurred while creating a new wallet from Scan QR using sweep all',
);
state = FailureState(e.toString());
}
}
Future<void> _connectToNode(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
TransactionInfo> TransactionInfo>
wallet) async { wallet) async {
@ -119,7 +172,7 @@ abstract class WalletCreationVMBase with Store {
Future< Future<
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
TransactionInfo>> createNewWalletWithoutSwitching( TransactionInfo>> _createNewWalletWithoutSwitching(
{dynamic options, {dynamic options,
RestoredWallet? restoreWallet, RestoredWallet? restoreWallet,
bool regenerateName = false}) async { bool regenerateName = false}) async {
@ -142,7 +195,8 @@ abstract class WalletCreationVMBase with Store {
id: WalletBase.idFor(name, type), id: WalletBase.idFor(name, type),
name: name, name: name,
type: type, type: type,
isRecovery: isRecovery, //TODO(David): Ask Omar about this, was previous isRecovery
isRecovery: restoreWallet != null ? true : false,
restoreHeight: credentials.height ?? 0, restoreHeight: credentials.height ?? 0,
date: DateTime.now(), date: DateTime.now(),
path: path, path: path,
@ -160,7 +214,7 @@ abstract class WalletCreationVMBase with Store {
return wallet; return wallet;
} }
Future<void> sweepAllFundsToNewWallet( Future<void> _sweepAllFundsToNewWallet(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
TransactionInfo> TransactionInfo>
wallet, wallet,
@ -168,29 +222,39 @@ abstract class WalletCreationVMBase with Store {
TransactionInfo> TransactionInfo>
newWallet, newWallet,
WalletType type, WalletType type,
String newWalletAddress, String paymentId,
String paymentId) async { ) async {
final output = Output(wallet, _appStore.settingsStore, final output = Output(wallet, _appStore.settingsStore,
_fiatConversationStore, () => wallet.currency); _fiatConversationStore,
output.address = newWalletAddress; () => wallet.currency,
);
outputs.add(output);
output.address = newWallet.walletAddresses.address;
output.sendAll = true; output.sendAll = true;
output.note = 'testing the sweep all function'; output.note = 'testing the sweep all function';
final credentials = _credentials(type, wallet.currency.title, output); final credentials = _credentials(type, wallet.currency.title, output);
print('About to enter create function'); print('About to enter create function');
try { try {
await createTransaction(wallet, credentials); //* Simulating a send all transaction
// final currentNode = _appStore.settingsStore.getCurrentNode(type); await _createTransaction(wallet, credentials);
// final result = await walletCreationService.sweepAllFunds(currentNode, newWalletAddress, paymentId);
//* Switch back to new wallet await _commitTransaction();
_appStore.changeCurrentWallet(wallet);
await _walletInfoSource.deleteAt(0);
//* Add the new Wallet info to the walletInfoSource //* Add the new Wallet info to the walletInfoSource
await _walletInfoSource.add(newWallet.walletInfo); await _walletInfoSource.add(newWallet.walletInfo);
//* Switch to the new wallet
_appStore.changeCurrentWallet(newWallet);
//* Load the wallet to simulate a real wallet interaction environment
await loadCurrentWallet();
//* Approve authentication as successful //* Approve authentication as successful
_appStore.authenticationStore.allowed(); _appStore.authenticationStore.allowed();
print('Successfully done inisde sweep all'); print('Successfully done inisde sweep all');
state = ExecutedSuccessfullyState(); state = ExecutedSuccessfullyState();
} catch (e) { } catch (e) {
@ -244,8 +308,8 @@ abstract class WalletCreationVMBase with Store {
} }
} }
@action
Future<void> createTransaction(WalletBase wallet, Object credentials) async { Future<void> _createTransaction(WalletBase wallet, Object credentials) async {
try { try {
print('in here'); print('in here');
state = IsExecutingState(); state = IsExecutingState();
@ -257,6 +321,43 @@ abstract class WalletCreationVMBase with Store {
} }
} }
Future<void> _commitTransaction() async {
if (pendingTransaction == null) {
throw Exception(
"Pending transaction doesn't exist. It should not be happened.");
}
String address = outputs.fold('', (acc, value) {
return value.isParsedAddress
? acc + value.address + '\n' + value.extractedAddress + '\n\n'
: acc + value.address + '\n\n';
});
address = address.trim();
String note = outputs.fold('', (acc, value) {
return acc + value.note + '\n';
});
note = note.trim();
try {
await pendingTransaction!.commit();
if (pendingTransaction!.id.isNotEmpty) {
_appStore.settingsStore.shouldSaveRecipientAddress
? await transactionDescriptionBox.add(TransactionDescription(
id: pendingTransaction!.id,
recipientAddress: address,
transactionNote: note))
: await transactionDescriptionBox.add(TransactionDescription(
id: pendingTransaction!.id, transactionNote: note));
}
} catch (e) {
state = FailureState(e.toString());
}
}
WalletCredentials getCredentials(dynamic options) { WalletCredentials getCredentials(dynamic options) {
switch (type) { switch (type) {
case WalletType.monero: case WalletType.monero:
@ -287,149 +388,3 @@ abstract class WalletCreationVMBase with Store {
WalletCredentials credentials, RestoredWallet restoreWallet) => WalletCredentials credentials, RestoredWallet restoreWallet) =>
throw UnimplementedError(); throw UnimplementedError();
} }
// class SweepAllService {
// final AppStore _appStore;
// final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
// TransactionInfo> restoredWallet;
// final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
// TransactionInfo> newWallet;
// final FiatConversionStore _fiatConversationStore;
// final Box<WalletInfo> _walletInfoSource;
// final String? txId;
// SweepAllService(
// this._appStore,
// this.restoredWallet,
// this._fiatConversationStore,
// this._walletInfoSource,
// this.newWallet,
// this.txId,
// );
// Future<void> create() async {
// try {
// //* Connect to the Node first
// await connectToNode(restoredWallet);
// //* Switch wallet to that of the restoredWallet
// _appStore.changeCurrentWallet(restoredWallet);
// //* Load the restore wallet to imitate actual loading
// await loadCurrentWallet();
// //* Start the sync
// await restoredWallet.startSync();
// print('Before syncing starts');
// await syncCompleter.future;
// print('After syncing ends');
// // * Sweep all funds from restoredWallet to newWallet
// await sweepAllFundsToNewWallet(
// restoredWallet,
// restoredWallet.type,
// newWallet.walletAddresses.address,
// 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();
// } catch (e) {
// print('Errorrrrr');
// }
// }
// Future<void> connectToNode(
// WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
// TransactionInfo>
// wallet) async {
// final node = _appStore.settingsStore.getCurrentNode(wallet.type);
// await wallet.connectToNode(node: node);
// }
// Future<void> sweepAllFundsToNewWallet(
// WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
// 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);
// } catch (e) {
// log(e.toString());
// }
// }
// @action
// Future<void> createTransaction(WalletBase wallet, Object credentials) async {
// try {
// print('about to enter wallet create transaction function');
// final pendingTransaction = await wallet.createTransaction(credentials);
// print(pendingTransaction);
// } catch (e) {
// log(e.toString());
// }
// }
// Object _credentials(
// WalletType type, String cryptoCurrencyTitle, Output output) {
// switch (type) {
// case WalletType.bitcoin:
// final priority = _appStore.settingsStore.priority[type];
// if (priority == null) {
// throw Exception('Priority is null for wallet type: ${type}');
// }
// return bitcoin!
// .createBitcoinTransactionCredentials([output], priority: priority);
// case WalletType.litecoin:
// final priority = _appStore.settingsStore.priority[type];
// if (priority == null) {
// throw Exception('Priority is null for wallet type: ${type}');
// }
// return bitcoin!
// .createBitcoinTransactionCredentials([output], priority: priority);
// case WalletType.monero:
// final priority = _appStore.settingsStore.priority[type];
// if (priority == null) {
// throw Exception('Priority is null for wallet type: ${type}');
// }
// return monero!.createMoneroTransactionCreationCredentials(
// 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);
// default:
// throw Exception('Unexpected wallet type: ${type}');
// }
// }
// }

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
@ -18,11 +19,17 @@ part 'wallet_new_vm.g.dart';
class WalletNewVM = WalletNewVMBase with _$WalletNewVM; class WalletNewVM = WalletNewVMBase with _$WalletNewVM;
abstract class WalletNewVMBase extends WalletCreationVM with Store { abstract class WalletNewVMBase extends WalletCreationVM with Store {
WalletNewVMBase(AppStore appStore, WalletCreationService walletCreationService,FiatConversionStore fiatConversationStore, WalletNewVMBase(
AppStore appStore,
WalletCreationService walletCreationService,
FiatConversionStore fiatConversationStore,
Box<TransactionDescription> transactionDescriptionBox,
Box<WalletInfo> walletInfoSource, Box<WalletInfo> walletInfoSource,
{required WalletType type}) {required WalletType type})
: selectedMnemonicLanguage = '', : selectedMnemonicLanguage = '',
super(appStore, walletInfoSource, walletCreationService,fiatConversationStore, type: type, isRecovery: false); super(appStore, walletInfoSource, walletCreationService,
fiatConversationStore, transactionDescriptionBox,
type: type, isRecovery: false);
@observable @observable
String selectedMnemonicLanguage; String selectedMnemonicLanguage;

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -22,14 +23,19 @@ class WalletRestorationFromKeysVM = WalletRestorationFromKeysVMBase
abstract class WalletRestorationFromKeysVMBase extends WalletCreationVM abstract class WalletRestorationFromKeysVMBase extends WalletCreationVM
with Store { with Store {
WalletRestorationFromKeysVMBase(AppStore appStore, WalletRestorationFromKeysVMBase(AppStore appStore,
WalletCreationService walletCreationService, Box<WalletInfo> walletInfoSource,FiatConversionStore fiatConversationStore, WalletCreationService walletCreationService,
Box<WalletInfo> walletInfoSource,
FiatConversionStore fiatConversationStore,
Box<TransactionDescription> transactionDescriptionBox,
{required WalletType type, required this.language}) {required WalletType type, required this.language})
: height = 0, : height = 0,
viewKey = '', viewKey = '',
spendKey = '', spendKey = '',
wif = '', wif = '',
address = '', address = '',
super(appStore, walletInfoSource, walletCreationService, fiatConversationStore, type: type, isRecovery: true); super(appStore, walletInfoSource, walletCreationService,
fiatConversationStore, transactionDescriptionBox,
type: type, isRecovery: true);
@observable @observable
int height; int height;

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -22,10 +23,15 @@ class WalletRestorationFromSeedVM = WalletRestorationFromSeedVMBase
abstract class WalletRestorationFromSeedVMBase extends WalletCreationVM abstract class WalletRestorationFromSeedVMBase extends WalletCreationVM
with Store { with Store {
WalletRestorationFromSeedVMBase(AppStore appStore, WalletRestorationFromSeedVMBase(AppStore appStore,
WalletCreationService walletCreationService, Box<WalletInfo> walletInfoSource,FiatConversionStore fiatConversationStore, WalletCreationService walletCreationService,
Box<WalletInfo> walletInfoSource,
FiatConversionStore fiatConversationStore,
Box<TransactionDescription> transactionDescriptionBox,
{required WalletType type, required this.language, this.seed = ''}) {required WalletType type, required this.language, this.seed = ''})
: height = 0, : height = 0,
super(appStore, walletInfoSource, walletCreationService ,fiatConversationStore, type: type, isRecovery: true); super(appStore, walletInfoSource, walletCreationService,
fiatConversationStore, transactionDescriptionBox,
type: type, isRecovery: true);
@observable @observable
String seed; String seed;

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/mnemonic_length.dart'; import 'package:cake_wallet/core/mnemonic_length.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -24,7 +25,11 @@ class WalletRestoreViewModel = WalletRestoreViewModelBase
with _$WalletRestoreViewModel; with _$WalletRestoreViewModel;
abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,FiatConversionStore fiatConversationStore, WalletRestoreViewModelBase(
AppStore appStore,
WalletCreationService walletCreationService,
FiatConversionStore fiatConversationStore,
Box<TransactionDescription> transactionDescriptionBox,
Box<WalletInfo> walletInfoSource, Box<WalletInfo> walletInfoSource,
{required WalletType type}) {required WalletType type})
: availableModes = (type == WalletType.monero || type == WalletType.haven) : availableModes = (type == WalletType.monero || type == WalletType.haven)
@ -34,7 +39,9 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven, hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
isButtonEnabled = false, isButtonEnabled = false,
mode = WalletRestoreMode.seed, mode = WalletRestoreMode.seed,
super(appStore, walletInfoSource, walletCreationService, fiatConversationStore, type: type, isRecovery: true) { super(appStore, walletInfoSource, walletCreationService,
fiatConversationStore, transactionDescriptionBox,
type: type, isRecovery: true) {
isButtonEnabled = isButtonEnabled =
!hasSeedLanguageSelector && !hasBlockchainHeightLanguageSelector; !hasSeedLanguageSelector && !hasBlockchainHeightLanguageSelector;
walletCreationService.changeWalletType(type: type); walletCreationService.changeWalletType(type: type);