CW-673: Save Haven seeds to show it to the user after Haven removal (#1518)

* haven: backup seeds * haven backup fixes * ci fix * reorder build script * disable haven * properly call cw_haven code * [skip ci] update PR * Update evm_chain_transaction_history.dart remove print --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

cyan committed Dec 11, 2024 at 15:31 UTC e2a1d865afe2380cc9e814270ea98bfdf5456519
7 files changed +87 -14
cw_core/lib/hive_type_ids.dart
+2 -1
@@ -18,4 +18,5 @@ const SPL_TOKEN_TYPE_ID = 16;
18 const DERIVATION_INFO_TYPE_ID = 17;
19 const TRON_TOKEN_TYPE_ID = 18;
20 const HARDWARE_WALLET_TYPE_TYPE_ID = 19;
21 -const MWEB_UTXO_TYPE_ID = 20;
\ No newline at end of file
21 +const MWEB_UTXO_TYPE_ID = 20;
22 +const HAVEN_SEED_STORE_TYPE_ID = 21;
\ No newline at end of file
cw_evm/lib/evm_chain_transaction_history.dart
-1
@@ -84,7 +84,6 @@ abstract class EVMChainTransactionHistoryBase
84 _update(tx);
85 }
86 }
87 - print('doneee');
87 } catch (e) {
88 log(e.toString());
89 }
lib/entities/default_settings_migration.dart
+23 -9
@@ -1,9 +1,13 @@
1 import 'dart:convert';
2 import 'dart:io' show Directory, File, Platform;
3 import 'package:cake_wallet/bitcoin/bitcoin.dart';
4 +import 'package:cake_wallet/core/key_service.dart';
5 import 'package:cake_wallet/core/secure_storage.dart';
6 import 'package:cake_wallet/entities/exchange_api_mode.dart';
7 import 'package:cake_wallet/entities/fiat_api_mode.dart';
8 +import 'package:cake_wallet/entities/haven_seed_store.dart';
9 +import 'package:cake_wallet/haven/haven.dart';
10 +import 'package:cw_core/cake_hive.dart';
11 import 'package:cw_core/pathForWallet.dart';
12 import 'package:cake_wallet/entities/secret_store_key.dart';
13 import 'package:cw_core/root_dir.dart';
@@ -52,7 +56,8 @@ Future<void> defaultSettingsMigration(
56 required Box<Node> powNodes,
57 required Box<WalletInfo> walletInfoSource,
58 required Box<Trade> tradeSource,
55 - required Box<Contact> contactSource}) async {
59 + required Box<Contact> contactSource,
60 + required Box<HavenSeedStore> havenSeedStore}) async {
61 if (Platform.isIOS) {
62 await ios_migrate_v1(walletInfoSource, tradeSource, contactSource);
63 }
@@ -290,20 +295,22 @@ Future<void> defaultSettingsMigration(
295 );
296 break;
297 case 45:
293 - await updateWalletTypeNodesWithNewNode(
298 + await _backupHavenSeeds(havenSeedStore);
299 +
300 + updateWalletTypeNodesWithNewNode(
301 newNodeUri: 'matic.nownodes.io',
302 sharedPreferences: sharedPreferences,
303 nodes: nodes,
304 type: WalletType.polygon,
305 useSSL: true,
306 );
300 - await updateWalletTypeNodesWithNewNode(
301 - newNodeUri: 'eth.nownodes.io',
302 - sharedPreferences: sharedPreferences,
303 - nodes: nodes,
304 - type: WalletType.ethereum,
305 - useSSL: true,
306 - );
307 + updateWalletTypeNodesWithNewNode(
308 + newNodeUri: 'eth.nownodes.io',
309 + sharedPreferences: sharedPreferences,
310 + nodes: nodes,
311 + type: WalletType.ethereum,
312 + useSSL: true,
313 + );
314 default:
315 break;
316 }
@@ -318,6 +325,13 @@ Future<void> defaultSettingsMigration(
325 await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
326 }
327
328 +Future<void> _backupHavenSeeds(Box<HavenSeedStore> havenSeedStore) async {
329 + final future = haven?.backupHavenSeeds(havenSeedStore);
330 + if (future != null) {
331 + await future;
332 + }
333 + return;
334 +}
335 /// generic function for changing any wallet default node
336 /// instead of making a new function for each change
337 Future<void> _changeDefaultNode({
lib/entities/haven_seed_store.dart new
+19
@@ -0,0 +1,19 @@
1 +import 'package:cw_core/hive_type_ids.dart';
2 +import 'package:hive/hive.dart';
3 +
4 +part 'haven_seed_store.g.dart';
5 +
6 +@HiveType(typeId: HavenSeedStore.typeId)
7 +class HavenSeedStore extends HiveObject {
8 + HavenSeedStore({required this.id, this.seed});
9 +
10 + static const typeId = HAVEN_SEED_STORE_TYPE_ID;
11 + static const boxName = 'HavenSeedStore';
12 + static const boxKey = 'havenSeedStoreKey';
13 +
14 + @HiveField(0, defaultValue: '')
15 + String id;
16 +
17 + @HiveField(2)
18 + String? seed;
19 +}
lib/haven/cw_haven.dart
+17
@@ -307,6 +307,23 @@ class CWHaven extends Haven {
307 return havenTransactionInfo.accountIndex;
308 }
309
310 + @override
311 + Future<void> backupHavenSeeds(Box<HavenSeedStore> havenSeedStore) async {
312 + final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
313 + final wallets = walletInfoSource.values
314 + .where((element) => element.type == WalletType.haven);
315 + for (var w in wallets) {
316 + final walletService = HavenWalletService(walletInfoSource);
317 + final flutterSecureStorage = secureStorageShared;
318 + final keyService = KeyService(flutterSecureStorage);
319 + final password = await keyService.getWalletPassword(walletName: w.name);
320 + final wallet = await walletService.openWallet(w.name, password);
321 + await havenSeedStore.add(HavenSeedStore(id: wallet.id, seed: wallet.seed));
322 + wallet.close();
323 + }
324 + await havenSeedStore.flush();
325 + }
326 +
327 @override
328 WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
329 return HavenWalletService(walletInfoSource);
lib/main.dart
+16 -2
@@ -9,6 +9,7 @@ import 'package:cake_wallet/entities/contact.dart';
9 import 'package:cake_wallet/entities/default_settings_migration.dart';
10 import 'package:cake_wallet/entities/get_encryption_key.dart';
11 import 'package:cake_wallet/core/secure_storage.dart';
12 +import 'package:cake_wallet/entities/haven_seed_store.dart';
13 import 'package:cake_wallet/entities/language_service.dart';
14 import 'package:cake_wallet/entities/template.dart';
15 import 'package:cake_wallet/entities/transaction_description.dart';
@@ -164,6 +165,10 @@ Future<void> initializeAppConfigs() async {
165 CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter());
166 }
167
168 + if (!CakeHive.isAdapterRegistered(HavenSeedStore.typeId)) {
169 + CakeHive.registerAdapter(HavenSeedStoreAdapter());
170 + }
171 +
172 if (!CakeHive.isAdapterRegistered(MwebUtxo.typeId)) {
173 CakeHive.registerAdapter(MwebUtxoAdapter());
174 }
@@ -188,6 +193,12 @@ Future<void> initializeAppConfigs() async {
193 final anonpayInvoiceInfo = await CakeHive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
194 final unspentCoinsInfoSource = await CakeHive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
195
196 + final havenSeedStoreBoxKey =
197 + await getEncryptionKey(secureStorage: secureStorage, forKey: HavenSeedStore.boxKey);
198 + final havenSeedStore = await CakeHive.openBox<HavenSeedStore>(
199 + HavenSeedStore.boxName,
200 + encryptionKey: havenSeedStoreBoxKey);
201 +
202 await initialSetup(
203 sharedPreferences: await SharedPreferences.getInstance(),
204 nodes: nodes,
@@ -203,6 +214,7 @@ Future<void> initializeAppConfigs() async {
214 transactionDescriptions: transactionDescriptions,
215 secureStorage: secureStorage,
216 anonpayInvoiceInfo: anonpayInvoiceInfo,
217 + havenSeedStore: havenSeedStore,
218 initialMigrationVersion: 45,
219 );
220 }
@@ -222,7 +234,8 @@ Future<void> initialSetup(
234 required SecureStorage secureStorage,
235 required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
236 required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
225 - int initialMigrationVersion = 15}) async {
237 + required Box<HavenSeedStore> havenSeedStore,
238 + int initialMigrationVersion = 15, }) async {
239 LanguageService.loadLocaleList();
240 await defaultSettingsMigration(
241 secureStorage: secureStorage,
@@ -232,7 +245,8 @@ Future<void> initialSetup(
245 contactSource: contactSource,
246 tradeSource: tradesSource,
247 nodes: nodes,
235 - powNodes: powNodes);
248 + powNodes: powNodes,
249 + havenSeedStore: havenSeedStore);
250 await setup(
251 walletInfoSource: walletInfoSource,
252 nodeSource: nodes,
tool/configure.dart
+10 -1
@@ -656,7 +656,14 @@ import 'package:cw_core/output_info.dart';
656 import 'package:cake_wallet/view_model/send/output.dart';
657 import 'package:cw_core/wallet_service.dart';
658 import 'package:hive/hive.dart';
659 -import 'package:cw_core/crypto_currency.dart';""";
659 +import 'package:cw_core/crypto_currency.dart';
660 +import 'package:cake_wallet/core/key_service.dart';
661 +import 'package:cake_wallet/core/secure_storage.dart';
662 +import 'package:cake_wallet/entities/haven_seed_store.dart';
663 +import 'package:cw_core/cake_hive.dart';
664 +import 'package:cw_core/wallet_info.dart';
665 +import 'package:cw_core/wallet_type.dart';
666 +""";
667 const havenCWHeaders = """
668 import 'package:cw_core/get_height_by_date.dart';
669 import 'package:cw_core/monero_amount_format.dart';
@@ -679,6 +686,7 @@ import 'package:cw_haven/mnemonics/french.dart';
686 import 'package:cw_haven/mnemonics/italian.dart';
687 import 'package:cw_haven/haven_transaction_creation_credentials.dart';
688 import 'package:cw_haven/api/balance_list.dart';
689 +import 'package:cw_haven/haven_wallet_service.dart';
690 """;
691 const havenCwPart = "part 'cw_haven.dart';";
692 const havenContent = """
@@ -779,6 +787,7 @@ abstract class Haven {
787 void onStartup();
788 int getTransactionInfoAccountId(TransactionInfo tx);
789 WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource);
790 + Future<void> backupHavenSeeds(Box<HavenSeedStore> havenSeedStore);
791 CryptoCurrency assetOfTransaction(TransactionInfo tx);
792 List<AssetRate> getAssetRate();
793 }