From ae97e50bf43b32f8804f13dfc404d3aa9bf5f2c8 Mon Sep 17 00:00:00 2001 From: fosse Date: Mon, 9 Oct 2023 14:08:14 -0400 Subject: [PATCH] debatably better refactoring of derivationInfo, migration needed --- cw_bitcoin/lib/bitcoin_wallet.dart | 36 ++++++++-------- .../bitcoin_wallet_creation_credentials.dart | 22 ++++++---- cw_bitcoin/lib/bitcoin_wallet_service.dart | 14 +++--- cw_core/lib/hive_type_ids.dart | 3 +- cw_core/lib/wallet_credentials.dart | 6 +-- cw_core/lib/wallet_info.dart | 24 +++++------ cw_nano/lib/nano_wallet.dart | 4 +- .../lib/nano_wallet_creation_credentials.dart | 25 +++++++---- cw_nano/lib/nano_wallet_service.dart | 12 +++--- lib/main.dart | 4 ++ lib/nano/cw_nano.dart | 1 + .../screens/restore/wallet_restore_page.dart | 43 ++++++++----------- lib/view_model/wallet_creation_vm.dart | 3 +- lib/view_model/wallet_new_vm.dart | 9 ++-- lib/view_model/wallet_restore_view_model.dart | 27 +++++++++--- 15 files changed, 127 insertions(+), 106 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index d70915b2c..0bc6f5acd 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -38,7 +38,6 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialBalance: initialBalance, seedBytes: seedBytes, currency: CryptoCurrency.btc) { - // in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here) // the sideHd derivation path = m/84'/0'/0'/1 (account 1, index unspecified here) walletAddresses = BitcoinWalletAddresses(walletInfo, @@ -47,9 +46,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, mainHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType) - .derivePath(walletInfo.derivationPath!), - sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath( - walletInfo.derivationPath!.substring(0, walletInfo.derivationPath!.length - 1) + "1"), + .derivePath(walletInfo.derivationInfo!.derivationPath!), + sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath(walletInfo + .derivationInfo!.derivationPath! + .substring(0, walletInfo.derivationInfo!.derivationPath!.length - 1) + + "1"), networkType: networkType); } @@ -64,14 +65,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { int initialChangeAddressIndex = 0}) async { late Uint8List seedBytes; - switch (walletInfo.derivationType) { - case DerivationType.electrum2: - seedBytes = await mnemonicToSeedBytes(mnemonic); - break; + switch (walletInfo.derivationInfo?.derivationType) { case DerivationType.bip39: - default: seedBytes = await bip39.mnemonicToSeed(mnemonic); break; + case DerivationType.electrum2: + default: + seedBytes = await mnemonicToSeedBytes(mnemonic); + break; } return BitcoinWallet( @@ -94,20 +95,17 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { }) async { final snp = await ElectrumWallletSnapshot.load(name, walletInfo.type, password); - walletInfo.derivationType = snp.derivationType; - walletInfo.derivationPath = snp.derivationPath; + walletInfo.derivationInfo ??= DerivationInfo( + derivationType: snp.derivationType ?? DerivationType.electrum2, + derivationPath: snp.derivationPath, + ); // set the default if not present: - if (walletInfo.derivationPath == null) { - walletInfo.derivationPath = "m/0'/1"; - } - if (walletInfo.derivationType == null) { - walletInfo.derivationType = DerivationType.electrum2; - } + walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? "m/0'/1"; late Uint8List seedBytes; - switch (walletInfo.derivationType) { + switch (walletInfo.derivationInfo!.derivationType) { case DerivationType.electrum2: seedBytes = await mnemonicToSeedBytes(snp.mnemonic); break; @@ -128,4 +126,4 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex); } -} \ No newline at end of file +} diff --git a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart index 6eaf55586..3089fc7e4 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart @@ -2,8 +2,11 @@ import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; class BitcoinNewWalletCredentials extends WalletCredentials { - BitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo}) + BitcoinNewWalletCredentials( + {required String name, WalletInfo? walletInfo, this.derivationType, this.derivationPath}) : super(name: name, walletInfo: walletInfo); + DerivationType? derivationType; + String? derivationPath; } class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials { @@ -11,16 +14,17 @@ class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials { required String name, required String password, required this.mnemonic, + WalletInfo? walletInfo, DerivationType? derivationType, String? derivationPath, - WalletInfo? walletInfo, }) : super( - name: name, - password: password, - walletInfo: walletInfo, - derivationType: derivationType, - derivationPath: derivationPath, - ); + name: name, + password: password, + walletInfo: walletInfo, + derivationInfo: DerivationInfo( + derivationType: derivationType, + derivationPath: derivationPath, + )); final String mnemonic; } @@ -31,4 +35,4 @@ class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials { : super(name: name, password: password, walletInfo: walletInfo); final String wif; -} \ No newline at end of file +} diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart index 5cd26cb54..7be406a72 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart @@ -46,13 +46,13 @@ class BitcoinWalletService extends WalletService create(BitcoinNewWalletCredentials credentials) async { - // default derivation type/path for bitcoin wallets: - if (credentials.walletInfo!.derivationType == null) { - credentials.walletInfo!.derivationType = DerivationType.electrum2; - } - if (credentials.walletInfo!.derivationPath == null) { - credentials.walletInfo!.derivationPath = "m/0'/1"; - } + // set default if not present: + DerivationType derivationType = credentials.derivationType ?? DerivationType.electrum2; + String derivationPath = credentials.derivationPath ?? "m/0'/1"; + // only set if not in the walletInfo already: + credentials.walletInfo!.derivationInfo ??= + DerivationInfo(derivationType: derivationType, derivationPath: derivationPath); + final wallet = await BitcoinWalletBase.create( mnemonic: await generateElectrumMnemonic(strength: 132), password: credentials.password!, diff --git a/cw_core/lib/hive_type_ids.dart b/cw_core/lib/hive_type_ids.dart index 4d4d1a6a8..da3865e8e 100644 --- a/cw_core/lib/hive_type_ids.dart +++ b/cw_core/lib/hive_type_ids.dart @@ -13,4 +13,5 @@ const ADDRESS_INFO_TYPE_ID = 11; const ERC20_TOKEN_TYPE_ID = 12; const NANO_ACCOUNT_TYPE_ID = 13; const POW_NODE_TYPE_ID = 14; -const DERIVATION_TYPE_TYPE_ID = 15; \ No newline at end of file +const DERIVATION_TYPE_TYPE_ID = 15; +const DERIVATION_INFO_TYPE_ID = 16; \ No newline at end of file diff --git a/cw_core/lib/wallet_credentials.dart b/cw_core/lib/wallet_credentials.dart index 0cdf892bd..dd69b7326 100644 --- a/cw_core/lib/wallet_credentials.dart +++ b/cw_core/lib/wallet_credentials.dart @@ -6,14 +6,12 @@ abstract class WalletCredentials { this.height, this.walletInfo, this.password, - this.derivationType, - this.derivationPath, + this.derivationInfo, }); final String name; final int? height; String? password; - DerivationType? derivationType; - String? derivationPath; WalletInfo? walletInfo; + DerivationInfo? derivationInfo; } diff --git a/cw_core/lib/wallet_info.dart b/cw_core/lib/wallet_info.dart index e1dcf2d94..c67665c70 100644 --- a/cw_core/lib/wallet_info.dart +++ b/cw_core/lib/wallet_info.dart @@ -21,10 +21,10 @@ enum DerivationType { @HiveField(5) electrum2, } - -class DerivationInfo { +@HiveType(typeId: DerivationInfo.typeId) +class DerivationInfo extends HiveObject { DerivationInfo({ - required this.derivationType, + this.derivationType, this.derivationPath, this.balance = "", this.address = "", @@ -33,10 +33,12 @@ class DerivationInfo { this.description, }); + static const typeId = DERIVATION_INFO_TYPE_ID; + String balance; String address; int height; - final DerivationType derivationType; + DerivationType? derivationType; String? derivationPath; final String? script_type; final String? description; @@ -57,8 +59,7 @@ class WalletInfo extends HiveObject { this.yatEid, this.yatLastUsedAddressRaw, this.showIntroCakePayCard, - this.derivationType, - this.derivationPath) + this.derivationInfo) : _yatLastUsedAddressController = StreamController.broadcast(); factory WalletInfo.external({ @@ -74,8 +75,7 @@ class WalletInfo extends HiveObject { bool? showIntroCakePayCard, String yatEid = '', String yatLastUsedAddressRaw = '', - DerivationType? derivationType, - String? derivationPath, + DerivationInfo? derivationInfo, }) { return WalletInfo( id, @@ -90,8 +90,7 @@ class WalletInfo extends HiveObject { yatEid, yatLastUsedAddressRaw, showIntroCakePayCard, - derivationType, - derivationPath); + derivationInfo); } static const typeId = WALLET_INFO_TYPE_ID; @@ -143,10 +142,7 @@ class WalletInfo extends HiveObject { List? usedAddresses; @HiveField(16) - DerivationType? derivationType; - - @HiveField(17) - String? derivationPath; + DerivationInfo? derivationInfo; String get yatLastUsedAddress => yatLastUsedAddressRaw ?? ''; diff --git a/cw_nano/lib/nano_wallet.dart b/cw_nano/lib/nano_wallet.dart index da50f4ebb..fc8b8ff9e 100644 --- a/cw_nano/lib/nano_wallet.dart +++ b/cw_nano/lib/nano_wallet.dart @@ -42,7 +42,7 @@ abstract class NanoWalletBase }) : syncStatus = NotConnectedSyncStatus(), _password = password, _mnemonic = mnemonic, - _derivationType = walletInfo.derivationType!, + _derivationType = walletInfo.derivationInfo!.derivationType!, _isTransactionUpdating = false, _client = NanoClient(), walletAddresses = NanoWalletAddresses(walletInfo), @@ -354,7 +354,7 @@ abstract class NanoWalletBase derivationType = DerivationType.nano; } - walletInfo.derivationType = derivationType; + walletInfo.derivationInfo ??= DerivationInfo(derivationType: derivationType); return NanoWallet( walletInfo: walletInfo, diff --git a/cw_nano/lib/nano_wallet_creation_credentials.dart b/cw_nano/lib/nano_wallet_creation_credentials.dart index 84531e24a..a713d3e44 100644 --- a/cw_nano/lib/nano_wallet_creation_credentials.dart +++ b/cw_nano/lib/nano_wallet_creation_credentials.dart @@ -2,8 +2,15 @@ import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; class NanoNewWalletCredentials extends WalletCredentials { - NanoNewWalletCredentials({required String name, String? password}) - : super(name: name, password: password); + NanoNewWalletCredentials({ + required String name, + String? password, + DerivationType? derivationType, + }) : super( + name: name, + password: password, + derivationInfo: DerivationInfo(derivationType: derivationType), + ); } class NanoRestoreWalletFromSeedCredentials extends WalletCredentials { @@ -14,11 +21,13 @@ class NanoRestoreWalletFromSeedCredentials extends WalletCredentials { String? password, DerivationType? derivationType, }) : super( - name: name, - password: password, - height: height, - derivationType: derivationType, - ); + name: name, + password: password, + height: height, + derivationInfo: DerivationInfo( + derivationType: derivationType, + height: height, + )); final String mnemonic; } @@ -38,4 +47,4 @@ class NanoRestoreWalletFromKeysCredentials extends WalletCredentials { final String seedKey; final DerivationType? derivationType; -} \ No newline at end of file +} diff --git a/cw_nano/lib/nano_wallet_service.dart b/cw_nano/lib/nano_wallet_service.dart index 2f183d1cc..85bd9cc78 100644 --- a/cw_nano/lib/nano_wallet_service.dart +++ b/cw_nano/lib/nano_wallet_service.dart @@ -28,11 +28,12 @@ class NanoWalletService extends WalletService create(NanoNewWalletCredentials credentials) async { // nano standard: - DerivationType derivationType = DerivationType.nano; String seedKey = NanoSeeds.generateSeed(); String mnemonic = NanoUtil.seedToMnemonic(seedKey); - credentials.walletInfo!.derivationType = derivationType; + // set default if not present: + DerivationType derivationType = credentials.derivationInfo?.derivationType ?? DerivationType.nano; + credentials.walletInfo!.derivationInfo ??= DerivationInfo(derivationType: derivationType); final wallet = NanoWallet( walletInfo: credentials.walletInfo!, @@ -88,7 +89,7 @@ class NanoWalletService extends WalletService initializeAppConfigs() async { if (!Hive.isAdapterRegistered(DERIVATION_TYPE_TYPE_ID)) { CakeHive.registerAdapter(DerivationTypeAdapter()); } + + if (!Hive.isAdapterRegistered(DERIVATION_INFO_TYPE_ID)) { + CakeHive.registerAdapter(DerivationInfoAdapter()); + } if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) { CakeHive.registerAdapter(WalletTypeAdapter()); diff --git a/lib/nano/cw_nano.dart b/lib/nano/cw_nano.dart index cd0f0ca8a..24b894b6e 100644 --- a/lib/nano/cw_nano.dart +++ b/lib/nano/cw_nano.dart @@ -96,6 +96,7 @@ class CWNano extends Nano { NanoNewWalletCredentials( name: name, password: password, + derivationType: DerivationType.nano, ); @override diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index 42b73106f..51c41c4fd 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -110,8 +110,9 @@ class WalletRestorePage extends BasePage { final GlobalKey walletRestoreFromSeedFormKey; final GlobalKey walletRestoreFromKeysFormKey; final FocusNode _blockHeightFocusNode; - DerivationType derivationType = DerivationType.unknown; - String? derivationPath = null; + // DerivationType derivationType = DerivationType.unknown; + // String? derivationPath = null; + DerivationInfo? derivationInfo; @override Widget body(BuildContext context) { @@ -294,8 +295,7 @@ class WalletRestorePage extends BasePage { } } - credentials['derivationType'] = this.derivationType; - credentials['derivationPath'] = this.derivationPath; + credentials['derivationInfo'] = this.derivationInfo; credentials['walletType'] = walletRestoreViewModel.type; return credentials; } @@ -330,10 +330,12 @@ class WalletRestorePage extends BasePage { List derivationTypes = await walletRestoreViewModel.getDerivationTypes(_credentials()); + DerivationInfo? dInfo; - if (derivationTypes[0] == DerivationType.unknown || derivationTypes.length > 1) { + if (derivationTypes.length > 1) { // push screen to choose the derivation type: - List derivations = await walletRestoreViewModel.getDerivationInfo(_credentials()); + List derivations = + await walletRestoreViewModel.getDerivationInfo(_credentials()); int derivationsWithHistory = 0; int derivationWithHistoryIndex = 0; @@ -343,34 +345,25 @@ class WalletRestorePage extends BasePage { derivationWithHistoryIndex = i; } } - - - DerivationInfo? derivationInfo; if (derivationsWithHistory > 1) { - derivationInfo = await Navigator.of(context).pushNamed(Routes.restoreWalletChooseDerivation, + dInfo = await Navigator.of(context).pushNamed(Routes.restoreWalletChooseDerivation, arguments: derivations) as DerivationInfo?; } else if (derivationsWithHistory == 1) { - derivationInfo = derivations[derivationWithHistoryIndex]; - } else if (derivationsWithHistory == 0) { - // default derivation: - derivationInfo = DerivationInfo( - derivationType: derivationTypes[0], - derivationPath: "m/0'/1", - height: 0, - ); + dInfo = derivations[derivationWithHistoryIndex]; } - if (derivationInfo == null) { + if (dInfo == null) { walletRestoreViewModel.state = InitialExecutionState(); return; } - this.derivationType = derivationInfo.derivationType; - this.derivationPath = derivationInfo.derivationPath; - } else { - // electrum derivation: - this.derivationType = derivationTypes[0]; - this.derivationPath = "m/0'/1"; + + this.derivationInfo = dInfo; + } + + // get the default derivation for this wallet type: + if (this.derivationInfo == null) { + this.derivationInfo = walletRestoreViewModel.getDefaultDerivation(); } walletRestoreViewModel.state = InitialExecutionState(); diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index aa1efe4d3..b22fe484c 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -65,8 +65,7 @@ abstract class WalletCreationVMBase with Store { dirPath: dirPath, address: '', showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven, - derivationPath: credentials.derivationPath, - derivationType: credentials.derivationType, + derivationInfo: credentials.derivationInfo, ); credentials.walletInfo = walletInfo; final wallet = restoreWallet != null diff --git a/lib/view_model/wallet_new_vm.dart b/lib/view_model/wallet_new_vm.dart index 04da7190e..0b83aa434 100644 --- a/lib/view_model/wallet_new_vm.dart +++ b/lib/view_model/wallet_new_vm.dart @@ -35,21 +35,20 @@ abstract class WalletNewVMBase extends WalletCreationVM 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); case WalletType.ethereum: return ethereum!.createEthereumNewWalletCredentials(name: name); case WalletType.nano: return nano!.createNanoNewWalletCredentials(name: name); default: - throw Exception('Unexpected type: ${type.toString()}');; + throw Exception('Unexpected type: ${type.toString()}'); + ; } } diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index d8ee2b6c1..6606c2660 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -70,8 +70,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { final password = generateWalletPassword(); final height = options['height'] as int? ?? 0; name = options['name'] as String; - DerivationType? derivationType = options["derivationType"] as DerivationType?; - String? derivationPath = options["derivationPath"] as String?; + DerivationInfo? derivationInfo = options["derivationInfo"] as DerivationInfo?; if (mode == WalletRestoreMode.seed) { final seed = options['seed'] as String; @@ -84,8 +83,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { name: name, mnemonic: seed, password: password, - derivationType: derivationType, - derivationPath: derivationPath, + derivationType: derivationInfo?.derivationType, + derivationPath: derivationInfo?.derivationPath, ); case WalletType.litecoin: return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( @@ -101,7 +100,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { name: name, mnemonic: seed, password: password, - derivationType: derivationType, + derivationType: derivationInfo?.derivationType, ); default: break; @@ -223,6 +222,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { privateKey: seedKey, node: node, ); + case WalletType.litecoin: + return [DerivationType.electrum2]; default: break; } @@ -231,6 +232,22 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { return [DerivationType.def]; } + DerivationInfo getDefaultDerivation() { + switch (type) { + case WalletType.nano: + return DerivationInfo( + derivationType: DerivationType.nano, + ); + case WalletType.bitcoin: + case WalletType.litecoin: + default: + return DerivationInfo( + derivationType: DerivationType.electrum2, + derivationPath: "m/0'/1", + ); + } + } + @override Future process(WalletCredentials credentials) async { if (mode == WalletRestoreMode.keys) {