feat: initial hive -> SQLite (#2502)
What changed, and why it matters
This is a large internal refactor that replaces the Hive key-value database with SQLite for storing wallet metadata (names, addresses, derivation paths, etc.). It also migrates old Hive data to the new SQLite format. The change touches many wallet types and could affect wallet loading, backups, restores, renaming, deletion, and address book behavior. It is a feature/refactor commit, not a targeted security fix, but any bug in the migration or new SQL layer could lead to data loss or incorrect wallet selection.
Treat this as a high-risk refactor requiring thorough QA: verify one-way Hive-to-SQLite migration on iOS/Android/desktop, test backup/restore across old and new app versions, confirm wallet open/rename/delete/switching for each coin, and audit the new SQLite helpers for injection or race conditions in the full codebase. Do not deploy without regression testing, especially for users upgrading from older Hive-based versions.
Security signals we found
Large data-layer migration from Hive to SQLite with one-way migration logic
New SQL schema stores wallet metadata including derivation paths, addresses, hardware wallet type, and recovery flags
Multiple wallet services now throw generic Exception('Wallet not found') when SQLite lookup fails
Legacy Hive adapter retained to read old boxes and migrate them
Backup/restore code paths modified (backup_service.dart, backup_service_v3.dart, restore_from_backup_view_model.dart)
Address book and contact list storage moved to SQLite
No parameterized query issues visible in the supplied diff; queries use sqflite's where/whereArgs binding
Migration catches errors and continues, which could mask migration failures
Evidence from the diff
The commit swaps the Hive NoSQL store for an SQLite-backed store (sqflite/sqflite_common_ffi) for WalletInfo, DerivationInfo, and address maps. It introduces cw_core/lib/db/sqlite.dart with schema creation, a legacy wallet_info_legacy.dart adapter to read old Hive boxes, and a migration routine (performHiveMigration / migrateAllToSqlite). Wallet services across Bitcoin, Litecoin, Bitcoin Cash, Dogecoin, Monero, Wownero, Zano, Decred, Ethereum/Polygon/Base, Solana, Tron, and Nano are updated to use async WalletInfo.get/save/delete helpers instead of the Hive Box
Changed components
cw_core/lib/db/sqlite.dartcw_core/lib/wallet_info.dartcw_core/lib/wallet_info_legacy.dartcw_core/lib/wallet_addresses.dartlib/core/backup_service.dartlib/core/backup_service_v3.dartAll wallet service implementations (cw_bitcoin, cw_litecoin, cw_bitcoin_cash, cw_dogecoin, cw_monero, cw_wownero, cw_zano, cw_decred, cw_ethereum, cw_evm, cw_polygon, cw_base, cw_solana, cw_tron, cw_nano)lib/entities/wallet_manager.dartlib/store/app_store.dartlib/main.dartInspect captured patch +2624 / −918
diff --git a/.github/workflows/pr_test_build_linux.yml b/.github/workflows/pr_test_build_linux.yml
index 746bdcf..0e736ee 100644
--- a/.github/workflows/pr_test_build_linux.yml
+++ b/.github/workflows/pr_test_build_linux.yml
@@ -308,8 +308,8 @@ jobs:
rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet
exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart
- name: Test [cw_monero]
- timeout-minutes: 2
- run: cd cw_monero && flutter test
+ timeout-minutes: 15
+ run: cd cw_monero && flutter test --verbose
- name: Stop screen recording, encrypt and upload
if: always()
run: |
diff --git a/Dockerfile b/Dockerfile
index 5daa6a3..a4a0c19 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -59,6 +59,8 @@ RUN set -o xtrace \
ffmpeg network-manager x11-utils xvfb psmisc \
# extra linux dependencies so flutter doesn't complain
mesa-utils \
+ # database
+ libsqlite3-0 libsqlite3-dev \
# aarch64-linux-gnu dependencies
g++-aarch64-linux-gnu gcc-aarch64-linux-gnu \
# x86_64-linux-gnu dependencies
diff --git a/cw_base/lib/base_wallet.dart b/cw_base/lib/base_wallet.dart
index accb336..d1287da 100644
--- a/cw_base/lib/base_wallet.dart
+++ b/cw_base/lib/base_wallet.dart
@@ -22,6 +22,7 @@ class BaseWallet extends EVMChainWallet {
BaseWallet({
required super.walletInfo,
required super.password,
+ required super.derivationInfo,
super.mnemonic,
super.initialBalance,
super.privateKey,
@@ -150,6 +151,7 @@ class BaseWallet extends EVMChainWallet {
return BaseWallet(
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
password: password,
mnemonic: keysData.mnemonic,
privateKey: keysData.privateKey,
diff --git a/cw_base/lib/base_wallet_service.dart b/cw_base/lib/base_wallet_service.dart
index f7ef5e9..7457cbd 100644
--- a/cw_base/lib/base_wallet_service.dart
+++ b/cw_base/lib/base_wallet_service.dart
@@ -11,7 +11,6 @@ import 'package:cw_base/base_mnemonics_exception.dart';
class BaseWalletService extends EVMChainWalletService<BaseWallet> {
BaseWalletService(
- super.walletInfoSource,
super.isDirect, {
required this.client,
});
@@ -29,6 +28,7 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
final wallet = BaseWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
mnemonic: mnemonic,
password: credentials.password!,
passphrase: credentials.passphrase,
@@ -44,8 +44,10 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
@override
Future<BaseWallet> openWallet(String name, String password) async {
- final walletInfo =
- walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await BaseWallet.open(
@@ -84,6 +86,7 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
password: credentials.password!,
privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -97,14 +100,17 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
@override
Future<BaseWallet> restoreFromHardwareWallet(
EVMChainRestoreWalletFromHardware credentials) async {
- credentials.walletInfo!.derivationInfo = DerivationInfo(
- derivationType: DerivationType.bip39,
- derivationPath: "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0");
+ final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
+ derivationInfo.derivationType = DerivationType.bip39;
+ derivationInfo.derivationPath = "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0";
+ await derivationInfo.save();
credentials.walletInfo!.hardwareWalletType = credentials.hardwareWalletType;
credentials.walletInfo!.address = credentials.hwAccountData.address;
+ await credentials.walletInfo!.save();
final wallet = BaseWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: derivationInfo,
password: credentials.password!,
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -128,6 +134,7 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
passphrase: credentials.passphrase,
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -142,8 +149,10 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await BaseWallet.open(
password: password,
name: currentName,
@@ -158,6 +167,6 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ newWalletInfo.save();
}
}
diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index 241ef34..0a2b549 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -47,6 +47,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
BitcoinWalletBase({
required String password,
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Box<PayjoinSession> payjoinBox,
required EncryptionFileUtils encryptionFileUtils,
@@ -69,6 +70,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
xpub: xpub,
password: password,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
network: networkParam == null
? BitcoinNetwork.mainnet
@@ -133,7 +135,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
}) async {
late Uint8List seedBytes;
- switch (walletInfo.derivationInfo?.derivationType) {
+ final derivationInfo = await walletInfo.getDerivationInfo();
+
+ switch (derivationInfo.derivationType) {
case DerivationType.bip39:
seedBytes = await bip39.mnemonicToSeed(
mnemonic,
@@ -152,6 +156,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
passphrase: passphrase ?? "",
password: password,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialSilentAddresses: initialSilentAddresses,
@@ -212,20 +217,21 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
);
}
- walletInfo.derivationInfo ??= DerivationInfo();
+ final derivationInfo = await walletInfo.getDerivationInfo();
// set the default if not present:
- walletInfo.derivationInfo!.derivationPath ??=
+ derivationInfo.derivationPath ??=
snp?.derivationPath ?? electrum_path;
- walletInfo.derivationInfo!.derivationType ??=
+ derivationInfo.derivationType ??=
snp?.derivationType ?? DerivationType.electrum;
+ await derivationInfo.save();
Uint8List? seedBytes = null;
final mnemonic = keysData.mnemonic;
final passphrase = keysData.passphrase;
if (mnemonic != null) {
- switch (walletInfo.derivationInfo!.derivationType) {
+ switch (derivationInfo.derivationType) {
case DerivationType.electrum:
seedBytes =
await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
@@ -246,6 +252,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
password: password,
passphrase: passphrase,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp?.addresses,
initialSilentAddresses: snp?.silentAddresses,
@@ -484,7 +491,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
: null;
final index = addressEntry?.index ?? 0;
final isChange = addressEntry?.isHidden == true ? 1 : 0;
- final accountPath = walletInfo.derivationInfo?.derivationPath;
+ final derivationInfo = await walletInfo.getDerivationInfo();
+ final accountPath = derivationInfo.derivationPath;
final derivationPath =
accountPath != null ? "$accountPath/$isChange/$index" : null;
diff --git a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
index 9be8df3..55d301d 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
@@ -16,6 +16,10 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
walletInfo: walletInfo,
password: password,
passphrase: passphrase,
+ derivationInfo: DerivationInfo(
+ derivationType: derivationType,
+ derivationPath: derivationPath,
+ ),
);
final String? mnemonic;
diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart
index e5edfec..f742376 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_service.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart
@@ -23,10 +23,9 @@ class BitcoinWalletService extends WalletService<
BitcoinRestoreWalletFromSeedCredentials,
BitcoinWalletFromKeysCredentials,
BitcoinRestoreWalletFromHardware> {
- BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource,
+ BitcoinWalletService(this.unspentCoinsInfoSource,
this.payjoinSessionSource, this.isDirect);
- final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final Box<PayjoinSession> payjoinSessionSource;
final bool isDirect;
@@ -40,7 +39,13 @@ class BitcoinWalletService extends WalletService<
credentials.walletInfo?.network = network.value;
final String mnemonic;
- switch ( credentials.walletInfo?.derivationInfo?.derivationType) {
+ final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
+ derivationInfo.derivationType = credentials.derivationInfo?.derivationType ?? derivationInfo.derivationType;
+ derivationInfo.derivationPath = credentials.derivationInfo?.derivationPath ?? derivationInfo.derivationPath;
+ derivationInfo.description = credentials.derivationInfo?.description ?? derivationInfo.description;
+ derivationInfo.scriptType = credentials.derivationInfo?.scriptType ?? derivationInfo.scriptType;
+ await derivationInfo.save();
+ switch (derivationInfo.derivationType) {
case DerivationType.bip39:
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
@@ -51,6 +56,7 @@ class BitcoinWalletService extends WalletService<
mnemonic = await generateElectrumMnemonic();
break;
}
+ await derivationInfo.save();
final wallet = await BitcoinWalletBase.create(
mnemonic: mnemonic,
@@ -75,8 +81,10 @@ class BitcoinWalletService extends WalletService<
@override
Future<BitcoinWallet> openWallet(String name, String password) async {
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await BitcoinWalletBase.open(
password: password,
@@ -107,9 +115,11 @@ class BitcoinWalletService extends WalletService<
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where(
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList();
@@ -123,8 +133,10 @@ class BitcoinWalletService extends WalletService<
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await BitcoinWalletBase.open(
password: password,
name: currentName,
@@ -141,7 +153,7 @@ class BitcoinWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -149,15 +161,18 @@ class BitcoinWalletService extends WalletService<
{bool? isTestnet}) async {
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
credentials.walletInfo?.network = network.value;
- credentials.walletInfo?.derivationInfo?.derivationPath =
+ final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
+ derivationInfo.derivationPath =
credentials.hwAccountData.derivationPath;
final xpub = convertZpubToXpub(credentials.hwAccountData.xpub!);
+ await credentials.walletInfo!.save();
final wallet = await BitcoinWallet(
password: credentials.password!,
xpub: xpub,
walletInfo: credentials.walletInfo!,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
networkParam: network,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -180,6 +195,7 @@ class BitcoinWalletService extends WalletService<
password: credentials.password!,
xpub: xpub,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
networkParam: network,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index cf94845..816833c 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -63,6 +63,7 @@ abstract class ElectrumWalletBase
ElectrumWalletBase({
required String password,
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required this.network,
required this.encryptionFileUtils,
@@ -75,9 +76,8 @@ abstract class ElectrumWalletBase
ElectrumBalance? initialBalance,
CryptoCurrency? currency,
bool? alwaysScan,
- })
- : accountHD = getAccountHDWallet(currency, network, seedBytes, xpub,
- walletInfo.derivationInfo, walletInfo.hardwareWalletType),
+ }) : accountHD =
+ getAccountHDWallet(currency, network, seedBytes, xpub, derivationInfo, walletInfo.hardwareWalletType),
syncStatus = NotConnectedSyncStatus(),
_password = password,
_feeRates = <int>[],
@@ -100,9 +100,10 @@ abstract class ElectrumWalletBase
this.unspentCoinsInfo = unspentCoinsInfo,
this.isTestnet = !network.isMainnet,
this._mnemonic = mnemonic,
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
this.electrumClient = electrumClient ?? electrum.ElectrumClient();
this.walletInfo = walletInfo;
+ this.derivationInfo = derivationInfo;
transactionHistory = ElectrumTransactionHistory(
walletInfo: walletInfo,
password: password,
@@ -771,8 +772,9 @@ abstract class ElectrumWalletBase
pubKeyHex = hd.childKey(Bip32KeyIndex(utx.bitcoinAddressRecord.index)).publicKey.toHex();
}
+
final derivationPath =
- "${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? electrum_path)}"
+ "${_hardenedDerivationPath(derivationInfo.derivationPath ?? electrum_path)}"
"/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}"
"/${utx.bitcoinAddressRecord.index}";
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
@@ -981,7 +983,7 @@ abstract class ElectrumWalletBase
// Get Derivation path for change Address since it is needed in Litecoin and BitcoinCash hardware Wallets
final changeDerivationPath =
- "${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? "m/0'")}"
+ "${_hardenedDerivationPath(derivationInfo.derivationPath ?? "m/0'")}"
"/${changeAddress.isHidden ? "1" : "0"}"
"/${changeAddress.index}";
utxoDetails.publicKeys[address.pubKeyHash()] =
@@ -1447,8 +1449,8 @@ abstract class ElectrumWalletBase
? SegwitAddresType.p2wpkh.toString()
: walletInfo.addressPageType.toString(),
'balance': balance[currency]?.toJSON(),
- 'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index,
- 'derivationPath': walletInfo.derivationInfo?.derivationPath,
+ 'derivationTypeIndex': derivationInfo.derivationType?.index,
+ 'derivationPath': derivationInfo.derivationPath,
'silent_addresses': walletAddresses.silentAddresses.map((addr) => addr.toJSON()).toList(),
'silent_address_index': walletAddresses.currentSilentAddressIndex.toString(),
'mweb_addresses': walletAddresses.mwebAddresses.map((addr) => addr.toJSON()).toList(),
diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart
index eef2404..01c7171 100644
--- a/cw_bitcoin/lib/litecoin_wallet.dart
+++ b/cw_bitcoin/lib/litecoin_wallet.dart
@@ -60,6 +60,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
LitecoinWalletBase({
required String password,
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required EncryptionFileUtils encryptionFileUtils,
Uint8List? seedBytes,
@@ -80,6 +81,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
passphrase: passphrase,
xpub: xpub,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
network: LitecoinNetwork.mainnet,
initialAddresses: initialAddresses,
@@ -168,6 +170,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
{required String mnemonic,
required String password,
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required EncryptionFileUtils encryptionFileUtils,
String? passphrase,
@@ -179,7 +182,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
Map<String, int>? initialChangeAddressIndex}) async {
late Uint8List seedBytes;
- switch (walletInfo.derivationInfo?.derivationType) {
+ switch (derivationInfo.derivationType) {
case DerivationType.bip39:
seedBytes = await bip39.mnemonicToSeed(
mnemonic,
@@ -195,6 +198,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialMwebAddresses: initialMwebAddresses,
@@ -245,18 +249,17 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
);
}
- walletInfo.derivationInfo ??= DerivationInfo();
-
+ final derivationInfo = await walletInfo.getDerivationInfo();
// set the default if not present:
- walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
- walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
+ derivationInfo.derivationPath ??= snp?.derivationPath ?? electrum_path;
+ derivationInfo.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
Uint8List? seedBytes = null;
final mnemonic = keysData.mnemonic;
final passphrase = keysData.passphrase;
if (mnemonic != null) {
- switch (walletInfo.derivationInfo?.derivationType) {
+ switch (derivationInfo.derivationType) {
case DerivationType.bip39:
seedBytes = await bip39.mnemonicToSeed(
mnemonic,
@@ -269,12 +272,14 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
break;
}
}
+ await derivationInfo.save();
return LitecoinWallet(
mnemonic: keysData.mnemonic,
xpub: keysData.xPub,
password: password,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp?.addresses,
initialMwebAddresses: snp?.mwebAddresses,
diff --git a/cw_bitcoin/lib/litecoin_wallet_service.dart b/cw_bitcoin/lib/litecoin_wallet_service.dart
index 8405622..126b6a9 100644
--- a/cw_bitcoin/lib/litecoin_wallet_service.dart
+++ b/cw_bitcoin/lib/litecoin_wallet_service.dart
@@ -22,10 +22,8 @@ class LitecoinWalletService extends WalletService<
BitcoinRestoreWalletFromSeedCredentials,
BitcoinRestoreWalletFromWIFCredentials,
BitcoinRestoreWalletFromHardware> {
- LitecoinWalletService(
- this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
+ LitecoinWalletService(this.unspentCoinsInfoSource, this.isDirect);
- final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final bool isDirect;
@@ -35,7 +33,7 @@ class LitecoinWalletService extends WalletService<
@override
Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
final String mnemonic;
- switch (credentials.walletInfo?.derivationInfo?.derivationType) {
+ switch (credentials.derivationInfo?.derivationType) {
case DerivationType.bip39:
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
@@ -52,6 +50,7 @@ class LitecoinWalletService extends WalletService<
password: credentials.password!,
passphrase: credentials.passphrase,
walletInfo: credentials.walletInfo!,
+ derivationInfo: credentials.derivationInfo ?? (await credentials.walletInfo!.getDerivationInfo()),
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -68,8 +67,10 @@ class LitecoinWalletService extends WalletService<
@override
Future<LitecoinWallet> openWallet(String name, String password) async {
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await LitecoinWalletBase.open(
@@ -99,12 +100,14 @@ class LitecoinWalletService extends WalletService<
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
// if there are no more litecoin wallets left, cleanup the neutrino db and other files created by mwebd:
- if (walletInfoSource.values.where((info) => info.type == WalletType.litecoin).isEmpty) {
+ if ((await WalletInfo.selectList('type = ?', [WalletType.litecoin.index])).isEmpty) {
final appDirPath = (await getApplicationSupportDirectory()).path;
File neturinoDb = File('$appDirPath/neutrino.db');
File blockHeaders = File('$appDirPath/block_headers.bin');
@@ -136,8 +139,10 @@ class LitecoinWalletService extends WalletService<
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await LitecoinWalletBase.open(
password: password,
name: currentName,
@@ -153,7 +158,7 @@ class LitecoinWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -161,13 +166,17 @@ class LitecoinWalletService extends WalletService<
{bool? isTestnet}) async {
final network = isTestnet == true ? LitecoinNetwork.testnet : LitecoinNetwork.mainnet;
credentials.walletInfo?.network = network.value;
- credentials.walletInfo?.derivationInfo?.derivationPath =
+ final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
+ derivationInfo.derivationPath =
credentials.hwAccountData.derivationPath;
+ await derivationInfo.save();
+ credentials.walletInfo!.save();
final wallet = await LitecoinWallet(
password: credentials.password!,
xpub: credentials.hwAccountData.xpub,
walletInfo: credentials.walletInfo!,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -193,6 +202,7 @@ class LitecoinWalletService extends WalletService<
passphrase: credentials.passphrase,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: credentials.derivationInfo ?? (await credentials.walletInfo!.getDerivationInfo()),
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock
index ff31336..16ff716 100644
--- a/cw_bitcoin/pubspec.lock
+++ b/cw_bitcoin/pubspec.lock
@@ -1028,6 +1028,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.0"
+ sqflite:
+ dependency: transitive
+ description:
+ name: sqflite
+ sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ sqflite_android:
+ dependency: transitive
+ description:
+ name: sqflite_android
+ sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqflite_common:
+ dependency: transitive
+ description:
+ name: sqflite_common
+ sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.4+6"
+ sqflite_common_ffi:
+ dependency: transitive
+ description:
+ name: sqflite_common_ffi
+ sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4+4"
+ sqflite_darwin:
+ dependency: transitive
+ description:
+ name: sqflite_darwin
+ sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1+1"
+ sqflite_platform_interface:
+ dependency: transitive
+ description:
+ name: sqflite_platform_interface
+ sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqlite3:
+ dependency: transitive
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
stack_trace:
dependency: transitive
description:
@@ -1060,6 +1116,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart
index 5277740..3906572 100644
--- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart
+++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart
@@ -28,6 +28,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
required String mnemonic,
required String password,
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
@@ -41,6 +42,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
network: BitcoinCashNetwork.mainnet,
initialAddresses: initialAddresses,
@@ -81,6 +83,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
@@ -134,6 +137,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
mnemonic: keysData.mnemonic!,
password: password,
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp?.addresses.map((addr) {
try {
diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
index 931893e..1861b21 100644
--- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
+++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
@@ -18,9 +18,8 @@ class BitcoinCashWalletService extends WalletService<
BitcoinCashRestoreWalletFromSeedCredentials,
BitcoinCashRestoreWalletFromWIFCredentials,
BitcoinCashNewWalletCredentials> {
- BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
+ BitcoinCashWalletService(this.unspentCoinsInfoSource, this.isDirect);
- final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final bool isDirect;
@@ -51,8 +50,10 @@ class BitcoinCashWalletService extends WalletService<
@override
Future<BitcoinCashWallet> openWallet(String name, String password) async {
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await BitcoinCashWalletBase.open(
@@ -82,9 +83,11 @@ class BitcoinCashWalletService extends WalletService<
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where(
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList();
@@ -98,8 +101,10 @@ class BitcoinCashWalletService extends WalletService<
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await BitcoinCashWalletBase.open(
password: password,
name: currentName,
@@ -114,7 +119,7 @@ class BitcoinCashWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
diff --git a/cw_core/lib/db/sqlite.dart b/cw_core/lib/db/sqlite.dart
new file mode 100644
index 0000000..e8bba66
--- /dev/null
+++ b/cw_core/lib/db/sqlite.dart
@@ -0,0 +1,114 @@
+
+import 'package:sqflite/sqflite.dart';
+
+late Database db;
+
+Future<void> initDb({String? pathOverride}) async {
+ db = await openDatabase(
+ pathOverride ?? "cake.db",
+ version: 1,
+ onCreate: (Database db, int version) async {
+ await db.execute(
+ '''
+CREATE TABLE WalletInfo (
+ walletInfoId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ id TEXT NOT NULL,
+ name TEXT NOT NULL,
+ "type" INTEGER NOT NULL,
+ isRecovery INTEGER DEFAULT (0) NOT NULL,
+ walletInfoDerivationInfoId INTEGER NOT NULL,
+ restoreHeight INTEGER DEFAULT (0) NOT NULL,
+ "timestamp" INTEGER DEFAULT (0) NOT NULL,
+ dirPath TEXT NOT NULL,
+ "path" TEXT NOT NULL,
+ address TEXT NOT NULL,
+ yatEid TEXT,
+ yatLastUsedAddressRaw TEXT,
+ showIntroCakePayCard INTEGER DEFAULT (1),
+ addressPageType TEXT,
+ network TEXT,
+ hardwareWalletType INTEGER,
+ parentAddress TEXT,
+ hashedWalletIdentifier TEXT,
+ isNonSeedWallet INTEGER DEFAULT (0) NOT NULL,
+ sortOrder INTEGER DEFAULT (0) NOT NULL
+);
+''');
+
+ await db.execute(
+ '''
+CREATE TABLE WalletInfoDerivationInfo (
+ walletInfoDerivationInfoId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ address TEXT NOT NULL,
+ balance TEXT NOT NULL,
+ transactionsCount INTEGER DEFAULT (0) NOT NULL,
+ derivationType INTEGER NOT NULL,
+ derivationPath TEXT,
+ scriptType TEXT,
+ description TEXT
+);
+''');
+
+ await db.execute(
+ '''
+CREATE TABLE WalletInfoAddress (
+ walletInfoAddressId INTEGER PRIMARY KEY AUTOINCREMENT,
+ walletInfoId INTEGER,
+ "type" INTEGER NOT NULL,
+ address TEXT NOT NULL,
+ CONSTRAINT WalletInfoAddress_WalletInfo_FK FOREIGN KEY (walletInfoId) REFERENCES WalletInfo(walletInfoId)
+);
+''');
+
+ await db.execute(
+ '''
+CREATE TABLE WalletInfoAddressInfo (
+ walletInfoAddressInfoId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ walletInfoId INTEGER NOT NULL,
+ mapKey INTEGER NOT NULL,
+ mapValueAccountIndex INTEGER NOT NULL,
+ mapValueAddress TEXT NOT NULL,
+ mapValueLabel TEXT NOT NULL,
+ CONSTRAINT WalletInfoAddressInfo_WalletInfo_FK FOREIGN KEY (walletInfoId) REFERENCES WalletInfo(walletInfoId)
+);
+''');
+
+ await db.execute(
+ '''
+CREATE TABLE "WalletInfoAddressMap" (
+ walletInfoAddressMapId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ walletInfoId INTEGER NOT NULL,
+ addressKey TEXT NOT NULL,
+ addressValue TEXT NOT NULL,
+ CONSTRAINT WalletInfoAddress_WalletInfo_FK FOREIGN KEY (walletInfoId) REFERENCES WalletInfo(walletInfoId)
+);
+ '''
+ );
+ }
+ );
+}
+
+Future<Map<String, dynamic>> dumpDb() async {
+ try {
+ return await _dumpDb();
+ } catch (e) {
+ return {
+ "error": e.toString(),
+ "stackTrace": StackTrace.current.toString(),
+ };
+ }
+}
+
+Future<List<String>> _getTableNames() async {
+ final tableNames = await db.rawQuery('SELECT name FROM sqlite_master WHERE type = "table"');
+ return tableNames.map((e) => (e["name"]).toString()).toList();
+}
+
+Future<Map<String, dynamic>> _dumpDb() async {
+ final tableNames = await _getTableNames();
+ final ret = <String, dynamic>{};
+ for (final tableName in tableNames) {
+ ret[tableName] = await db.query(tableName);
+ }
+ return ret;
+}
\ No newline at end of file
diff --git a/cw_core/lib/wallet_addresses.dart b/cw_core/lib/wallet_addresses.dart
index b0da0e7..4d4d2c0 100644
--- a/cw_core/lib/wallet_addresses.dart
+++ b/cw_core/lib/wallet_addresses.dart
@@ -1,4 +1,3 @@
-import 'package:cw_core/address_info.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
@@ -9,8 +8,12 @@ abstract class WalletAddresses {
allAddressesMap = {},
addressInfos = {},
usedAddresses = {},
- hiddenAddresses = walletInfo.hiddenAddresses?.toSet() ?? {},
- manualAddresses = walletInfo.manualAddresses?.toSet() ?? {};
+ hiddenAddresses = {},
+ manualAddresses = {} {
+ walletInfo.getUsedAddresses().then((value) => usedAddresses = value);
+ walletInfo.getHiddenAddresses().then((value) => hiddenAddresses = value);
+ walletInfo.getManualAddresses().then((value) => manualAddresses = value);
+ }
final WalletInfo walletInfo;
@@ -47,7 +50,7 @@ abstract class WalletAddresses {
return tmp;
}
- Map<int, List<AddressInfo>> addressInfos;
+ Map<int, List<WalletInfoAddressInfo>> addressInfos;
Set<String> usedAddresses;
@@ -62,15 +65,13 @@ abstract class WalletAddresses {
Future<void> saveAddressesInBox() async {
try {
walletInfo.address = address;
- walletInfo.addresses = addressesMap;
- walletInfo.addressInfos = addressInfos;
- walletInfo.usedAddresses = usedAddresses.toList();
- walletInfo.hiddenAddresses = hiddenAddresses.toList();
- walletInfo.manualAddresses = manualAddresses.toList();
-
- if (walletInfo.isInBox) {
- await walletInfo.save();
- }
+ walletInfo.setAddresses(addressesMap);
+ walletInfo.setAddressInfos(addressInfos);
+ walletInfo.setUsedAddresses(usedAddresses.toList());
+ walletInfo.setHiddenAddresses(hiddenAddresses.toList());
+ walletInfo.setManualAddresses(manualAddresses.toList());
+
+ await walletInfo.save();
} catch (e) {
printV(e.toString());
}
diff --git a/cw_core/lib/wallet_addresses_with_account.dart b/cw_core/lib/wallet_addresses_with_account.dart
deleted file mode 100644
index 0dcf88d..0000000
--- a/cw_core/lib/wallet_addresses_with_account.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-import 'package:cw_core/wallet_addresses.dart';
-import 'package:cw_core/account_list.dart';
-import 'package:cw_core/wallet_info.dart';
-
-abstract class WalletAddressesWithAccount<T> extends WalletAddresses {
- WalletAddressesWithAccount(WalletInfo walletInfo) : super(walletInfo);
-
- // T get account;
-
- // set account(T account);
-
- AccountList<T> get accountList;
-}
\ No newline at end of file
diff --git a/cw_core/lib/wallet_base.dart b/cw_core/lib/wallet_base.dart
index 5ac3e9b..dfcc2c4 100644
--- a/cw_core/lib/wallet_base.dart
+++ b/cw_core/lib/wallet_base.dart
@@ -15,12 +15,13 @@ import 'package:cw_core/wallet_type.dart';
abstract class WalletBase<BalanceType extends Balance, HistoryType extends TransactionHistoryBase,
TransactionType extends TransactionInfo> {
- WalletBase(this.walletInfo);
+ WalletBase(this.walletInfo, this.derivationInfo);
static String idFor(String name, WalletType type) =>
walletTypeToString(type).toLowerCase() + '_' + name;
WalletInfo walletInfo;
+ DerivationInfo derivationInfo;
WalletType get type => walletInfo.type;
diff --git a/cw_core/lib/wallet_credentials.dart b/cw_core/lib/wallet_credentials.dart
index 30ae254..b9be31d 100644
--- a/cw_core/lib/wallet_credentials.dart
+++ b/cw_core/lib/wallet_credentials.dart
@@ -10,11 +10,7 @@ abstract class WalletCredentials {
this.passphrase,
this.derivationInfo,
this.hardwareWalletType,
- }) {
- if (this.walletInfo != null && derivationInfo != null) {
- this.walletInfo!.derivationInfo = derivationInfo;
- }
- }
+ });
final String name;
final int? height;
diff --git a/cw_core/lib/wallet_info.dart b/cw_core/lib/wallet_info.dart
index 4f849ec..2fd1801 100644
--- a/cw_core/lib/wallet_info.dart
+++ b/cw_core/lib/wallet_info.dart
@@ -1,47 +1,239 @@
import 'dart:async';
-import 'package:cw_core/address_info.dart';
+import 'package:cw_core/db/sqlite.dart';
import 'package:cw_core/hive_type_ids.dart';
+import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
-import 'package:hive/hive.dart';
-
-part 'wallet_info.g.dart';
+import 'package:sqflite/sqflite.dart';
+import 'package:cw_core/cake_hive.dart';
+import 'package:cw_core/wallet_info_legacy.dart' as wiLegacy;
+
+Future<void> performHiveMigration() async {
+ try {
+ if (!CakeHive.isAdapterRegistered(wiLegacy.WalletInfo.typeId)) {
+ CakeHive.registerAdapter(wiLegacy.WalletInfoAdapter());
+ }
+ if (!CakeHive.isAdapterRegistered(DERIVATION_TYPE_TYPE_ID)) {
+ CakeHive.registerAdapter(wiLegacy.DerivationTypeAdapter());
+ }
+ if (!CakeHive.isAdapterRegistered(wiLegacy.DerivationInfo.typeId)) {
+ CakeHive.registerAdapter(wiLegacy.DerivationInfoAdapter());
+ }
+ if (!CakeHive.isAdapterRegistered(HARDWARE_WALLET_TYPE_TYPE_ID)) {
+ CakeHive.registerAdapter(wiLegacy.HardwareWalletTypeAdapter());
+ }
+ final walletInfoBox = await CakeHive.openBox<wiLegacy.WalletInfo>(wiLegacy.WalletInfo.boxName);
+ await wiLegacy.WalletInfo.migrateAllToSqlite(walletInfoBox);
+ } catch (e) {
+ printV('Error performing Hive migration: $e, continuing anyway');
+ }
+}
-@HiveType(typeId: DERIVATION_TYPE_TYPE_ID)
enum DerivationType {
- @HiveField(0)
unknown,
- @HiveField(1)
def, // default is a reserved word
- @HiveField(2)
nano,
- @HiveField(3)
bip39,
- @HiveField(4)
electrum,
}
-@HiveType(typeId: HARDWARE_WALLET_TYPE_TYPE_ID)
enum HardwareWalletType {
- @HiveField(0)
ledger,
- @HiveField(1)
bitbox,
- @HiveField(2)
cupcake,
- @HiveField(3)
coldcard,
- @HiveField(4)
seedsigner,
- @HiveField(5)
keystone,
- @HiveField(6)
trezor,
}
-@HiveType(typeId: DerivationInfo.typeId)
-class DerivationInfo extends HiveObject {
+enum WalletInfoAddressType {
+ used,
+ hidden,
+ manual,
+}
+
+class WalletInfoAddressInfo {
+ WalletInfoAddressInfo({
+ this.id = 0,
+ required this.walletInfoId,
+ required this.mapKey,
+ required this.accountIndex,
+ required this.address,
+ required this.label,
+ });
+
+ int id;
+ int walletInfoId;
+ int mapKey;
+ int accountIndex;
+ String address;
+ String label;
+
+ static String get tableName => 'walletInfoAddressInfo';
+ static String get selfIdColumn => "${tableName}Id";
+
+ static Future<List<WalletInfoAddressInfo>> selectList(int walletInfoId) async {
+ final query = await db.query(tableName, where: 'walletInfoId = ?', whereArgs: [walletInfoId]);
+ return List.generate(query.length, (index) => WalletInfoAddressInfo.fromJson(query[index]));
+ }
+
+ static Future<int> deleteByWalletInfoId(int walletInfoId) async {
+ return await db.delete(tableName, where: 'walletInfoId = ?', whereArgs: [walletInfoId]);
+ }
+ static Future<int> insert({
+ required int walletInfoId,
+ required int mapKey,
+ required int accountIndex,
+ required String address,
+ required String label,
+ }) async {
+ return await db.insert(tableName, {
+ "walletInfoId": walletInfoId,
+ "mapKey": mapKey,
+ "mapValueAccountIndex": accountIndex,
+ "mapValueAddress": address,
+ "mapValueLabel": label,
+ });
+ }
+
+ Map<String, dynamic> toJson() {
+ return {
+ selfIdColumn: id,
+ "walletInfoId": walletInfoId,
+ "mapKey": mapKey,
+ "mapValueAccountIndex": accountIndex,
+ "mapValueAddress": address,
+ "mapValueLabel": label,
+ };
+ }
+
+ factory WalletInfoAddressInfo.fromJson(Map<String, dynamic> json) {
+ return WalletInfoAddressInfo(
+ id: json[selfIdColumn] as int,
+ walletInfoId: json['walletInfoId'] as int,
+ mapKey: json['mapKey'] as int,
+ accountIndex: json['mapValueAccountIndex'] as int,
+ address: json['mapValueAddress'] as String,
+ label: json['mapValueLabel'] as String,
+ );
+ }
+}
+
+class WalletInfoAddressMap {
+ WalletInfoAddressMap({
+ required this.id,
+ required this.walletInfoId,
+ required this.addressKey,
+ required this.addressValue,
+ });
+
+
+ int id;
+ int walletInfoId;
+ String addressKey;
+ String addressValue;
+
+ static String get tableName => 'walletInfoAddressMap';
+ static String get selfIdColumn => "${tableName}Id";
+
+ static Future<List<WalletInfoAddressMap>> selectList(int walletInfoId) async {
+ final query = await db.query(tableName, where: 'walletInfoId = ?', whereArgs: [walletInfoId]);
+ return List.generate(query.length, (index) => WalletInfoAddressMap.fromJson(query[index]));
+ }
+ static Future<int> deleteByWalletInfoId(int walletInfoId) async {
+ return await db.delete(tableName, where: 'walletInfoId = ?', whereArgs: [walletInfoId]);
+ }
+ static Future<int> insert(int walletInfoId, String addressKey, String addressValue) async {
+ return await db.insert(tableName, {
+ "walletInfoId": walletInfoId,
+ "addressKey": addressKey,
+ "addressValue": addressValue,
+ });
+ }
+
+ Map<String, dynamic> toJson() {
+ return {
+ selfIdColumn: id,
+ "walletInfoId": walletInfoId,
+ "addressKey": addressKey,
+ "addressValue": addressValue,
+ };
+ }
+
+ factory WalletInfoAddressMap.fromJson(Map<String, dynamic> json) {
+ return WalletInfoAddressMap(
+ id: json[selfIdColumn] as int,
+ walletInfoId: json['walletInfoId'] as int,
+ addressKey: json['addressKey'] as String,
+ addressValue: json['addressValue'] as String,
+ );
+ }
+}
+
+class WalletInfoAddress {
+ WalletInfoAddress({
+ this.id = 0,
+ required this.walletInfoId,
+ required this.type,
+ required this.address,
+ });
+
+ int id;
+ int walletInfoId;
+ WalletInfoAddressType type;
+ String address;
+
+ static String get tableName => 'walletInfoAddress';
+ static String get selfIdColumn => "${tableName}Id";
+
+ static Future<List<WalletInfoAddress>> selectList(int walletInfoId, WalletInfoAddressType type) async {
+ final query = await db.query(tableName, where: 'walletInfoId = ? AND type = ?', whereArgs: [walletInfoId, type.index]);
+ return List.generate(query.length, (index) => WalletInfoAddress.fromJson(query[index]));
+ }
+
+ static Future<int> deleteByAddress(int walletInfoId, WalletInfoAddressType type, String address) async {
+ return await db.delete(tableName, where: 'walletInfoId = ? AND type = ? AND address = ?', whereArgs: [walletInfoId, type.index, address]);
+ }
+
+ static Future<int> deleteByType(int walletInfoId, WalletInfoAddressType type) async {
+ return await db.delete(tableName, where: 'walletInfoId = ? AND type = ?', whereArgs: [walletInfoId, type.index]);
+ }
+
+ static Future<int> insert(int walletInfoId, WalletInfoAddressType type, String address) async {
+ final select = await db.query(tableName, where: 'walletInfoId = ? AND type = ? AND address = ?', whereArgs: [walletInfoId, type.index, address]);
+ if (select.isNotEmpty) {
+ return select[0][selfIdColumn] as int;
+ }
+ return await db.insert(tableName, {
+ "walletInfoId": walletInfoId,
+ "type": type.index,
+ "address": address,
+ });
+ }
+
+ Map<String, dynamic> toJson() {
+ return {
+ selfIdColumn: id,
+ "walletInfoId": walletInfoId,
+ "type": type.index,
+ "address": address,
+ };
+ }
+
+ factory WalletInfoAddress.fromJson(Map<String, dynamic> json) {
+ return WalletInfoAddress(
+ id: json[selfIdColumn] as int,
+ walletInfoId: json['walletInfoId'] as int,
+ type: WalletInfoAddressType.values[json['type'] as int],
+ address: json['address'] as String,
+ );
+ }
+}
+
+class DerivationInfo {
DerivationInfo({
+ this.id = 0,
this.derivationType,
this.derivationPath,
this.balance = "",
@@ -51,33 +243,77 @@ class DerivationInfo extends HiveObject {
this.description,
});
- static const typeId = DERIVATION_INFO_TYPE_ID;
+ int id;
- @HiveField(0, defaultValue: '')
- String address;
+ static String get tableName => 'walletInfoDerivationInfo';
+ static String get selfIdColumn => "${tableName}Id";
- @HiveField(1, defaultValue: '')
+ String address;
String balance;
-
- @HiveField(2, defaultValue: 0)
int transactionsCount;
-
- @HiveField(3)
DerivationType? derivationType;
-
- @HiveField(4)
String? derivationPath;
+ String? scriptType;
+ String? description;
+
+ static Future<List<DerivationInfo>> selectList(String where, List<dynamic> whereArgs) async {
+ final query = await db.query(
+ tableName,
+ columns: [
+ selfIdColumn,
+ 'address',
+ 'balance',
+ 'transactionsCount',
+ 'derivationType',
+ 'derivationPath',
+ 'scriptType',
+ 'description',
+ ],
+ where: where.isNotEmpty ? where : "1 = 1",
+ whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
+ );
+ return List.generate(query.length, (index) => DerivationInfo.fromJson(query[index]));
+ }
- @HiveField(5)
- final String? scriptType;
+ Map<String, dynamic> toJson() {
+ return {
+ selfIdColumn: id,
+ "address": address,
+ "balance": balance,
+ "transactionsCount": transactionsCount,
+ "derivationType": derivationType?.index,
+ "derivationPath": derivationPath,
+ "scriptType": scriptType,
+ "description": description,
+ };
+ }
- @HiveField(6)
- final String? description;
+ factory DerivationInfo.fromJson(Map<String, dynamic> json ) {
+ return DerivationInfo(
+ id: json[selfIdColumn] as int,
+ derivationType: DerivationType.values[json['derivationType'] as int? ?? 0],
+ derivationPath: json['derivationPath'] as String?,
+ balance: json['balance'] as String? ?? "",
+ address: json['address'] as String? ?? "",
+ transactionsCount: json['transactionsCount'] as int? ?? 0,
+ scriptType: json['scriptType'] as String?,
+ description: json['description'] as String?,
+ );
+ }
+
+ Future<int> save() async {
+ final json = toJson();
+ if (json[selfIdColumn] == 0) {
+ json[selfIdColumn] = null;
+ }
+ id = await db.insert(tableName, json, conflictAlgorithm: ConflictAlgorithm.replace);
+ return id;
+ }
}
-@HiveType(typeId: WalletInfo.typeId)
-class WalletInfo extends HiveObject {
+class WalletInfo {
WalletInfo(
+ this.internalId,
this.id,
this.name,
this.type,
@@ -90,11 +326,12 @@ class WalletInfo extends HiveObject {
this.yatEid,
this.yatLastUsedAddressRaw,
this.showIntroCakePayCard,
- this.derivationInfo,
+ this.derivationInfoId,
this.hardwareWalletType,
this.parentAddress,
this.hashedWalletIdentifier,
this.isNonSeedWallet,
+ this.sortOrder,
) : _yatLastUsedAddressController = StreamController<String>.broadcast();
factory WalletInfo.external({
@@ -110,13 +347,15 @@ class WalletInfo extends HiveObject {
bool? showIntroCakePayCard,
String yatEid = '',
String yatLastUsedAddressRaw = '',
- DerivationInfo? derivationInfo,
+ int? derivationInfoId,
HardwareWalletType? hardwareWalletType,
String? parentAddress,
String? hashedWalletIdentifier,
bool? isNonSeedWallet,
+ int? sortOrder,
}) {
return WalletInfo(
+ 0,
id,
name,
type,
@@ -129,96 +368,135 @@ class WalletInfo extends HiveObject {
yatEid,
yatLastUsedAddressRaw,
showIntroCakePayCard,
- derivationInfo,
+ derivationInfoId ?? -1,
hardwareWalletType,
parentAddress,
hashedWalletIdentifier,
isNonSeedWallet ?? false,
+ sortOrder ?? 0,
);
}
- static const typeId = WALLET_INFO_TYPE_ID;
- static const boxName = 'WalletInfo';
+ static String get tableName => 'walletInfo';
+ static String get selfIdColumn => "${tableName}Id";
- @HiveField(0, defaultValue: '')
- String id;
+ int internalId;
- @HiveField(1, defaultValue: '')
+ String id;
String name;
-
- @HiveField(2)
WalletType type;
-
- @HiveField(3, defaultValue: false)
bool isRecovery;
-
- @HiveField(4, defaultValue: 0)
int restoreHeight;
-
- @HiveField(5, defaultValue: 0)
int timestamp;
-
- @HiveField(6, defaultValue: '')
String dirPath;
-
- @HiveField(7, defaultValue: '')
String path;
-
- @HiveField(8, defaultValue: '')
String address;
+ Future<Map<String, String>> getAddresses() async {
+ final list = await WalletInfoAddressMap.selectList(internalId);
+ return Map.fromEntries(list.map((e) => MapEntry(e.addressKey, e.addressValue)));
+ }
- @HiveField(10)
- Map<String, String>? addresses;
+ Future<void> setAddresses(Map<String, String> addresses) async {
+ await WalletInfoAddressMap.deleteByWalletInfoId(internalId);
+ final keys = addresses.keys.toList();
+ for (final address in keys) {
+ await WalletInfoAddressMap.insert(internalId, address, addresses[address]!);
+ }
+ }
- @HiveField(11)
String? yatEid;
-
- @HiveField(12)
String? yatLastUsedAddressRaw;
-
- @HiveField(13)
bool? showIntroCakePayCard;
+ Future<Map<int, List<WalletInfoAddressInfo>>> getAddressInfos() async {
+ final list = await WalletInfoAddressInfo.selectList(internalId);
+ final ret = <int, List<WalletInfoAddressInfo>>{};
+ for (final e in list) {
+ ret[e.mapKey] ??= [];
+ ret[e.mapKey]!.add(e);
+ }
+ return ret;
+ }
- @HiveField(14)
- Map<int, List<AddressInfo>>? addressInfos;
+ Future<void> setAddressInfos(Map<int, List<WalletInfoAddressInfo>> addressInfos) async {
+ await WalletInfoAddressInfo.deleteByWalletInfoId(internalId);
+ final entries = addressInfos.entries.toList();
+ for (final addressInfo in entries) {
+ for (final info in addressInfo.value) {
+ await WalletInfoAddressInfo.insert(
+ walletInfoId: internalId,
+ mapKey: addressInfo.key,
+ accountIndex: info.accountIndex,
+ address: info.address,
+ label: info.label,
+ );
+ }
+ }
+ }
- @HiveField(15)
- List<String>? usedAddresses;
+ Future<Set<String>> getUsedAddresses() async {
+ final list = await WalletInfoAddress.selectList(internalId, WalletInfoAddressType.used);
+ return list.map((e) => e.address).toSet();
+ }
+ Future<void> setUsedAddresses(List<String> addresses) async {
+ await WalletInfoAddress.deleteByType(internalId, WalletInfoAddressType.used);
+ for (final address in addresses) {
+ await WalletInfoAddress.insert(internalId, WalletInfoAddressType.used, address);
+ }
+ }
- @deprecated
- @HiveField(16)
- DerivationType? derivationType; // no longer used
+ Future<Set<String>> getHiddenAddresses() async {
+ final list = await WalletInfoAddress.selectList(internalId, WalletInfoAddressType.hidden);
+ return list.map((e) => e.address).toSet();
+ }
+ Future<void> setHiddenAddresses(List<String> addresses) async {
+ await WalletInfoAddress.deleteByType(internalId, WalletInfoAddressType.hidden);
+ for (final address in addresses) {
+ await WalletInfoAddress.insert(internalId, WalletInfoAddressType.hidden, address);
+ }
+ }
- @deprecated
- @HiveField(17)
- String? derivationPath; // no longer used
+ Future<Set<String>> getManualAddresses() async {
+ final list = await WalletInfoAddress.selectList(internalId, WalletInfoAddressType.manual);
+ return list.map((e) => e.address).toSet();
+ }
+ Future<void> setManualAddresses(List<String> addresses) async {
+ await WalletInfoAddress.deleteByType(internalId, WalletInfoAddressType.manual);
+ for (final address in addresses) {
+ await WalletInfoAddress.insert(internalId, WalletInfoAddressType.manual, address);
+ }
+ }
- @HiveField(18)
- String? addressPageType;
+ Future<void> addAddress(String address, WalletInfoAddressType type) async {
+ await WalletInfoAddress.insert(internalId, type, address);
+ }
- @HiveField(19)
+ String? addressPageType;
String? network;
-
- @HiveField(20)
- DerivationInfo? derivationInfo;
-
- @HiveField(21)
+ int derivationInfoId;
+ DerivationInfo? _derivationInfo;
+ Future<DerivationInfo> getDerivationInfo() async {
+ if (_derivationInfo != null) {
+ return _derivationInfo!;
+ }
+ final list = await DerivationInfo.selectList('walletInfoDerivationInfoId = ?', [derivationInfoId]);
+ if (list.isEmpty) {
+ final di = DerivationInfo(
+ id: 0,
+ derivationType: DerivationType.unknown,
+ );
+ derivationInfoId = await di.save();
+ _derivationInfo = di;
+ return di;
+ }
+ _derivationInfo = list[0];
+ return _derivationInfo!;
+ }
HardwareWalletType? hardwareWalletType;
-
- @HiveField(22)
String? parentAddress;
-
- @HiveField(23)
- List<String>? hiddenAddresses;
-
- @HiveField(24)
- List<String>? manualAddresses;
-
- @HiveField(25)
String? hashedWalletIdentifier;
-
- @HiveField(26, defaultValue: false)
bool isNonSeedWallet;
+
+ int sortOrder;
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
@@ -248,6 +526,90 @@ class WalletInfo extends HiveObject {
StreamController<String> _yatLastUsedAddressController;
+ Map<String, dynamic> toJson() => {
+ selfIdColumn: internalId,
+ "id": id,
+ "name": name,
+ "type": type.index,
+ "isRecovery": isRecovery ? 1 : 0,
+ "restoreHeight": restoreHeight,
+ "timestamp": timestamp,
+ "dirPath": dirPath,
+ "path": path,
+ "address": address,
+ "yatEid": yatEid,
+ "yatLastUsedAddressRaw": yatLastUsedAddressRaw,
+ "showIntroCakePayCard": showIntroCakePayCard == true ? 1 : 0, // SQL regression: null -> false
+ "walletInfoDerivationInfoId": derivationInfoId,
+ "hardwareWalletType": hardwareWalletType?.index,
+ "parentAddress": parentAddress,
+ "hashedWalletIdentifier": hashedWalletIdentifier,
+ "isNonSeedWallet": isNonSeedWallet ? 1 : 0,
+ "sortOrder": sortOrder,
+ };
+
+ factory WalletInfo.fromJson(Map<String, dynamic> json) {
+ return WalletInfo(
+ json[selfIdColumn] as int,
+ json['id'] as String,
+ json['name'] as String,
+ WalletType.values[json['type'] as int],
+ (json['isRecovery'] as int) == 1,
+ json['restoreHeight'] as int,
+ json['timestamp'] as int,
+ json['dirPath'] as String,
+ json['path'] as String,
+ json['address'] as String,
+ json['yatEid'] as String?,
+ json['yatLastUsedAddressRaw'] as String?,
+ (json['showIntroCakePayCard'] as int) == 1,
+ json['walletInfoDerivationInfoId'] as int,
+ json['hardwareWalletType'] == null ? null : HardwareWalletType.values[json['hardwareWalletType'] as int],
+ json['parentAddress'] as String?,
+ json['hashedWalletIdentifier'] as String?,
+ (json['isNonSeedWallet'] as int) == 1,
+ json['sortOrder'] as int? ?? 0,
+ );
+ }
+
+ Future<int> save() async {
+ final json = toJson();
+ if (json[selfIdColumn] == 0) {
+ json[selfIdColumn] = null;
+ }
+ if (_derivationInfo != null) {
+ derivationInfoId = await _derivationInfo!.save();
+ }
+ internalId = await db.insert(tableName, json, conflictAlgorithm: ConflictAlgorithm.replace);
+ return internalId;
+ }
+
+ static Future<int> delete(WalletInfo walletInfo) async {
+ return await db.delete(tableName, where: 'id = ?', whereArgs: [walletInfo.id]);
+ }
+
+ static Future<List<WalletInfo>> selectList(String where, List<dynamic> whereArgs, {String orderBy = 'sortOrder'}) async {
+ final list = await db.query(
+ tableName,
+ where: where.isNotEmpty ? where : "1 = 1",
+ whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
+ orderBy: orderBy,
+ );
+ return List.generate(list.length, (index) => WalletInfo.fromJson(list[index]));
+ }
+
+ static Future<List<WalletInfo>> getAll() async {
+ return selectList('', []);
+ }
+
+ static Future<WalletInfo?> get(String name, WalletType type) async {
+ final list = await selectList('name = ? AND type = ?', [name, type.index]);
+ if (list.isEmpty) {
+ return null;
+ }
+ return list[0];
+ }
+
Future<void> updateRestoreHeight(int height) async {
restoreHeight = height;
await save();
diff --git a/cw_core/lib/wallet_info_legacy.dart b/cw_core/lib/wallet_info_legacy.dart
new file mode 100644
index 0000000..502edeb
--- /dev/null
+++ b/cw_core/lib/wallet_info_legacy.dart
@@ -0,0 +1,308 @@
+// NOTE: This code was generated by Hive, but since Hive is on the way out, this
+// code no longer uses hive generators, so when we get rid of hive we also will
+// be able to get rid of
+
+import 'dart:async';
+
+import 'package:cw_core/utils/print_verbose.dart';
+import 'package:cw_core/wallet_info.dart' as newWi;
+import 'package:cw_core/address_info.dart';
+import 'package:cw_core/hive_type_ids.dart';
+import 'package:cw_core/wallet_type.dart';
+import 'package:hive/hive.dart';
+
+part 'wallet_info_legacy.part.dart';
+
+// // @HiveType(typeId: DERIVATION_TYPE_TYPE_ID)
+// enum DerivationType {
+// // @HiveField(0)
+// unknown,
+// // @HiveField(1)
+// def, // default is a reserved word
+// // @HiveField(2)
+// nano,
+// // @HiveField(3)
+// bip39,
+// // @HiveField(4)
+// electrum,
+// }
+
+// // @HiveType(typeId: HARDWARE_WALLET_TYPE_TYPE_ID)
+// enum HardwareWalletType {
+// // @HiveField(0)
+// ledger,
+// }
+
+// @HiveType(typeId: DerivationInfo.typeId)
+class DerivationInfo extends HiveObject {
+ DerivationInfo({
+ this.derivationType,
+ this.derivationPath,
+ this.balance = "",
+ this.address = "",
+ this.transactionsCount = 0,
+ this.scriptType,
+ this.description,
+ });
+
+ static const typeId = DERIVATION_INFO_TYPE_ID;
+
+ // @HiveField(0, defaultValue: '')
+ String address;
+
+ // @HiveField(1, defaultValue: '')
+ String balance;
+
+ // @HiveField(2, defaultValue: 0)
+ int transactionsCount;
+
+ // @HiveField(3)
+ newWi.DerivationType? derivationType;
+
+ // @HiveField(4)
+ String? derivationPath;
+
+ // @HiveField(5)
+ final String? scriptType;
+
+ // @HiveField(6)
+ final String? description;
+}
+
+// @HiveType(typeId: WalletInfo.typeId)
+class WalletInfo extends HiveObject {
+ WalletInfo(
+ this.id,
+ this.name,
+ this.type,
+ this.isRecovery,
+ this.restoreHeight,
+ this.timestamp,
+ this.dirPath,
+ this.path,
+ this.address,
+ this.yatEid,
+ this.yatLastUsedAddressRaw,
+ this.showIntroCakePayCard,
+ this.derivationInfo,
+ this.hardwareWalletType,
+ this.parentAddress,
+ this.hashedWalletIdentifier,
+ this.isNonSeedWallet,
+ ) : _yatLastUsedAddressController = StreamController<String>.broadcast();
+
+ factory WalletInfo.external({
+ required String id,
+ required String name,
+ required WalletType type,
+ required bool isRecovery,
+ required int restoreHeight,
+ required DateTime date,
+ required String dirPath,
+ required String path,
+ required String address,
+ bool? showIntroCakePayCard,
+ String yatEid = '',
+ String yatLastUsedAddressRaw = '',
+ DerivationInfo? derivationInfo,
+ newWi.HardwareWalletType? hardwareWalletType,
+ String? parentAddress,
+ String? hashedWalletIdentifier,
+ bool? isNonSeedWallet,
+ }) {
+ return WalletInfo(
+ id,
+ name,
+ type,
+ isRecovery,
+ restoreHeight,
+ date.millisecondsSinceEpoch,
+ dirPath,
+ path,
+ address,
+ yatEid,
+ yatLastUsedAddressRaw,
+ showIntroCakePayCard,
+ derivationInfo,
+ hardwareWalletType,
+ parentAddress,
+ hashedWalletIdentifier,
+ isNonSeedWallet ?? false,
+ );
+ }
+
+ static const typeId = WALLET_INFO_TYPE_ID;
+ static const boxName = 'WalletInfo';
+
+ // @HiveField(0, defaultValue: '')
+ String id;
+
+ // @HiveField(1, defaultValue: '')
+ String name;
+
+ // @HiveField(2)
+ WalletType type;
+
+ // @HiveField(3, defaultValue: false)
+ bool isRecovery;
+
+ // @HiveField(4, defaultValue: 0)
+ int restoreHeight;
+
+ // @HiveField(5, defaultValue: 0)
+ int timestamp;
+
+ // @HiveField(6, defaultValue: '')
+ String dirPath;
+
+ // @HiveField(7, defaultValue: '')
+ String path;
+
+ // @HiveField(8, defaultValue: '')
+ String address;
+
+ // @HiveField(10)
+ Map<String, String>? addresses;
+
+ // @HiveField(11)
+ String? yatEid;
+
+ // @HiveField(12)
+ String? yatLastUsedAddressRaw;
+
+ // @HiveField(13)
+ bool? showIntroCakePayCard;
+
+ // @HiveField(14)
+ Map<int, List<AddressInfo>>? addressInfos;
+
+ // @HiveField(15)
+ List<String>? usedAddresses;
+
+ @deprecated
+ // @HiveField(16)
+ newWi.DerivationType? derivationType; // no longer used
+
+ @deprecated
+ // @HiveField(17)
+ String? derivationPath; // no longer used
+
+ // @HiveField(18)
+ String? addressPageType;
+
+ // @HiveField(19)
+ String? network;
+
+ // @HiveField(20)
+ DerivationInfo? derivationInfo;
+
+ // @HiveField(21)
+ newWi.HardwareWalletType? hardwareWalletType;
+
+ // @HiveField(22)
+ String? parentAddress;
+
+ // @HiveField(23)
+ List<String>? hiddenAddresses;
+
+ // @HiveField(24)
+ List<String>? manualAddresses;
+
+ // @HiveField(25)
+ String? hashedWalletIdentifier;
+
+ // @HiveField(26, defaultValue: false)
+ bool isNonSeedWallet;
+
+ String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
+
+ set yatLastUsedAddress(String address) {
+ yatLastUsedAddressRaw = address;
+ _yatLastUsedAddressController.add(address);
+ }
+
+ String get yatEmojiId => yatEid ?? '';
+
+ bool get isShowIntroCakePayCard {
+ if (showIntroCakePayCard == null) {
+ return type != WalletType.haven;
+ }
+ return showIntroCakePayCard!;
+ }
+
+ bool get isHardwareWallet => hardwareWalletType != null;
+
+ DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp);
+
+ Stream<String> get yatLastUsedAddressStream => _yatLastUsedAddressController.stream;
+
+ StreamController<String> _yatLastUsedAddressController;
+
+ Future<void> updateRestoreHeight(int height) async {
+ restoreHeight = height;
+ await save();
+ }
+
+ Future<void> migrateToSqlite() async {
+ final di = newWi.DerivationInfo(
+ id: 0,
+ derivationType: derivationInfo?.derivationType ?? derivationType ?? newWi.DerivationType.unknown,
+ derivationPath: derivationInfo?.derivationPath ?? derivationPath ?? '',
+ );
+ final derivationInfoId = await di.save();
+ final walletInfo = newWi.WalletInfo(
+ 0,
+ id,
+ name,
+ type,
+ isRecovery,
+ restoreHeight,
+ timestamp,
+ dirPath,
+ path,
+ address,
+ yatEid,
+ yatLastUsedAddressRaw,
+ showIntroCakePayCard,
+ derivationInfoId,
+ hardwareWalletType,
+ parentAddress,
+ hashedWalletIdentifier,
+ isNonSeedWallet,
+ 0,
+ );
+ final wiId = await walletInfo.save();
+ for (final address in usedAddresses ?? <String>[]) {
+ await newWi.WalletInfoAddress.insert(wiId, newWi.WalletInfoAddressType.used, address);
+ }
+ for (final address in hiddenAddresses ?? <String>[]) {
+ await newWi.WalletInfoAddress.insert(wiId, newWi.WalletInfoAddressType.hidden, address);
+ }
+ for (final address in manualAddresses ?? <String>[]) {
+ await newWi.WalletInfoAddress.insert(wiId, newWi.WalletInfoAddressType.manual, address);
+ }
+ for (int i = 0; i < (addressInfos?.length ?? 0); i++) {
+ for (final address in addressInfos![i] ?? <AddressInfo>[]) {
+ await newWi.WalletInfoAddressInfo.insert(
+ walletInfoId: wiId,
+ mapKey: i,
+ accountIndex: address.accountIndex??0,
+ address: address.address,
+ label: address.label,
+ );
+ }
+ }
+ await walletInfo.setAddresses(addresses ?? <String, String>{});
+ }
+
+ static Future<void> migrateAllToSqlite(final Box<WalletInfo> box) async {
+ printV('Migrating WalletInfo to SQLite: start');
+ final sw = Stopwatch()..start();
+ final list = box.values.toList();
+ for (final wi in list) {
+ await wi.migrateToSqlite();
+ await wi.delete();
+ }
+ printV('Migrating WalletInfo to SQLite: end (${sw.elapsedMilliseconds}ms)');
+ }
+}
diff --git a/cw_core/lib/wallet_info_legacy.part.dart b/cw_core/lib/wallet_info_legacy.part.dart
new file mode 100644
index 0000000..d58826e
--- /dev/null
+++ b/cw_core/lib/wallet_info_legacy.part.dart
@@ -0,0 +1,287 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'wallet_info_legacy.dart';
+
+// **************************************************************************
+// TypeAdapterGenerator
+// **************************************************************************
+
+class DerivationInfoAdapter extends TypeAdapter<DerivationInfo> {
+ @override
+ final int typeId = 17;
+
+ @override
+ DerivationInfo read(BinaryReader reader) {
+ final numOfFields = reader.readByte();
+ final fields = <int, dynamic>{
+ for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
+ };
+ return DerivationInfo(
+ derivationType: fields[3] as newWi.DerivationType?,
+ derivationPath: fields[4] as String?,
+ balance: fields[1] == null ? '' : fields[1] as String,
+ address: fields[0] == null ? '' : fields[0] as String,
+ transactionsCount: fields[2] == null ? 0 : fields[2] as int,
+ scriptType: fields[5] as String?,
+ description: fields[6] as String?,
+ );
+ }
+
+ @override
+ void write(BinaryWriter writer, DerivationInfo obj) {
+ writer
+ ..writeByte(7)
+ ..writeByte(0)
+ ..write(obj.address)
+ ..writeByte(1)
+ ..write(obj.balance)
+ ..writeByte(2)
+ ..write(obj.transactionsCount)
+ ..writeByte(3)
+ ..write(obj.derivationType)
+ ..writeByte(4)
+ ..write(obj.derivationPath)
+ ..writeByte(5)
+ ..write(obj.scriptType)
+ ..writeByte(6)
+ ..write(obj.description);
+ }
+
+ @override
+ int get hashCode => typeId.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is DerivationInfoAdapter &&
+ runtimeType == other.runtimeType &&
+ typeId == other.typeId;
+}
+
+class WalletInfoAdapter extends TypeAdapter<WalletInfo> {
+ @override
+ final int typeId = 4;
+
+ @override
+ WalletInfo read(BinaryReader reader) {
+ final numOfFields = reader.readByte();
+ final fields = <int, dynamic>{
+ for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
+ };
+ return WalletInfo(
+ fields[0] == null ? '' : fields[0] as String,
+ fields[1] == null ? '' : fields[1] as String,
+ fields[2] as WalletType,
+ fields[3] == null ? false : fields[3] as bool,
+ fields[4] == null ? 0 : fields[4] as int,
+ fields[5] == null ? 0 : fields[5] as int,
+ fields[6] == null ? '' : fields[6] as String,
+ fields[7] == null ? '' : fields[7] as String,
+ fields[8] == null ? '' : fields[8] as String,
+ fields[11] as String?,
+ fields[12] as String?,
+ fields[13] as bool?,
+ fields[20] as DerivationInfo?,
+ fields[21] as newWi.HardwareWalletType?,
+ fields[22] as String?,
+ fields[25] as String?,
+ fields[26] == null ? false : fields[26] as bool,
+ )
+ ..addresses = (fields[10] as Map?)?.cast<String, String>()
+ ..addressInfos = (fields[14] as Map?)?.map((dynamic k, dynamic v) =>
+ MapEntry(k as int, (v as List).cast<AddressInfo>()))
+ ..usedAddresses = (fields[15] as List?)?.cast<String>()
+ ..derivationType = fields[16] as newWi.DerivationType?
+ ..derivationPath = fields[17] as String?
+ ..addressPageType = fields[18] as String?
+ ..network = fields[19] as String?
+ ..hiddenAddresses = (fields[23] as List?)?.cast<String>()
+ ..manualAddresses = (fields[24] as List?)?.cast<String>();
+ }
+
+ @override
+ void write(BinaryWriter writer, WalletInfo obj) {
+ writer
+ ..writeByte(26)
+ ..writeByte(0)
+ ..write(obj.id)
+ ..writeByte(1)
+ ..write(obj.name)
+ ..writeByte(2)
+ ..write(obj.type)
+ ..writeByte(3)
+ ..write(obj.isRecovery)
+ ..writeByte(4)
+ ..write(obj.restoreHeight)
+ ..writeByte(5)
+ ..write(obj.timestamp)
+ ..writeByte(6)
+ ..write(obj.dirPath)
+ ..writeByte(7)
+ ..write(obj.path)
+ ..writeByte(8)
+ ..write(obj.address)
+ ..writeByte(10)
+ ..write(obj.addresses)
+ ..writeByte(11)
+ ..write(obj.yatEid)
+ ..writeByte(12)
+ ..write(obj.yatLastUsedAddressRaw)
+ ..writeByte(13)
+ ..write(obj.showIntroCakePayCard)
+ ..writeByte(14)
+ ..write(obj.addressInfos)
+ ..writeByte(15)
+ ..write(obj.usedAddresses)
+ ..writeByte(16)
+ ..write(obj.derivationType)
+ ..writeByte(17)
+ ..write(obj.derivationPath)
+ ..writeByte(18)
+ ..write(obj.addressPageType)
+ ..writeByte(19)
+ ..write(obj.network)
+ ..writeByte(20)
+ ..write(obj.derivationInfo)
+ ..writeByte(21)
+ ..write(obj.hardwareWalletType)
+ ..writeByte(22)
+ ..write(obj.parentAddress)
+ ..writeByte(23)
+ ..write(obj.hiddenAddresses)
+ ..writeByte(24)
+ ..write(obj.manualAddresses)
+ ..writeByte(25)
+ ..write(obj.hashedWalletIdentifier)
+ ..writeByte(26)
+ ..write(obj.isNonSeedWallet);
+ }
+
+ @override
+ int get hashCode => typeId.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is WalletInfoAdapter &&
+ runtimeType == other.runtimeType &&
+ typeId == other.typeId;
+}
+
+class DerivationTypeAdapter extends TypeAdapter<newWi.DerivationType> {
+ @override
+ final int typeId = 15;
+
+ @override
+ newWi.DerivationType read(BinaryReader reader) {
+ switch (reader.readByte()) {
+ case 0:
+ return newWi.DerivationType.unknown;
+ case 1:
+ return newWi.DerivationType.def;
+ case 2:
+ return newWi.DerivationType.nano;
+ case 3:
+ return newWi.DerivationType.bip39;
+ case 4:
+ return newWi.DerivationType.electrum;
+ default:
+ return newWi.DerivationType.unknown;
+ }
+ }
+
+ @override
+ void write(BinaryWriter writer, newWi.DerivationType obj) {
+ switch (obj) {
+ case newWi.DerivationType.unknown:
+ writer.writeByte(0);
+ break;
+ case newWi.DerivationType.def:
+ writer.writeByte(1);
+ break;
+ case newWi.DerivationType.nano:
+ writer.writeByte(2);
+ break;
+ case newWi.DerivationType.bip39:
+ writer.writeByte(3);
+ break;
+ case newWi.DerivationType.electrum:
+ writer.writeByte(4);
+ break;
+ }
+ }
+
+ @override
+ int get hashCode => typeId.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is DerivationTypeAdapter &&
+ runtimeType == other.runtimeType &&
+ typeId == other.typeId;
+}
+
+class HardwareWalletTypeAdapter extends TypeAdapter<newWi.HardwareWalletType> {
+ @override
+ final int typeId = 19;
+
+ @override
+ newWi.HardwareWalletType read(BinaryReader reader) {
+ switch (reader.readByte()) {
+ case 0:
+ return newWi.HardwareWalletType.ledger;
+ case 1:
+ return newWi.HardwareWalletType.bitbox;
+ case 2:
+ return newWi.HardwareWalletType.cupcake;
+ case 3:
+ return newWi.HardwareWalletType.coldcard;
+ case 4:
+ return newWi.HardwareWalletType.seedsigner;
+ case 5:
+ return newWi.HardwareWalletType.keystone;
+ case 6:
+ return newWi.HardwareWalletType.trezor;
+ default:
+ return newWi.HardwareWalletType.ledger;
+ }
+ }
+
+ @override
+ void write(BinaryWriter writer, newWi.HardwareWalletType obj) {
+ switch (obj) {
+ case newWi.HardwareWalletType.ledger:
+ writer.writeByte(0);
+ break;
+ case newWi.HardwareWalletType.bitbox:
+ writer.writeByte(1);
+ break;
+ case newWi.HardwareWalletType.cupcake:
+ writer.writeByte(2);
+ break;
+ case newWi.HardwareWalletType.coldcard:
+ writer.writeByte(3);
+ break;
+ case newWi.HardwareWalletType.seedsigner:
+ writer.writeByte(4);
+ break;
+ case newWi.HardwareWalletType.keystone:
+ writer.writeByte(5);
+ break;
+ case newWi.HardwareWalletType.trezor:
+ writer.writeByte(6);
+ break;
+ }
+ }
+
+ @override
+ int get hashCode => typeId.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is HardwareWalletTypeAdapter &&
+ runtimeType == other.runtimeType &&
+ typeId == other.typeId;
+}
diff --git a/cw_core/lib/wallet_service.dart b/cw_core/lib/wallet_service.dart
index 8512685..016f3cc 100644
--- a/cw_core/lib/wallet_service.dart
+++ b/cw_core/lib/wallet_service.dart
@@ -64,5 +64,5 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
/// Check if the Wallet requires a hardware wallet to be connected during
/// the opening flow. (Currently only the case for Monero)
- bool requireHardwareWalletConnection(String name) => false;
+ Future<bool> requireHardwareWalletConnection(String name) async => false;
}
diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock
index 2cfa935..918a81a 100644
--- a/cw_core/pubspec.lock
+++ b/cw_core/pubspec.lock
@@ -674,6 +674,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
+ sqflite:
+ dependency: "direct main"
+ description:
+ name: sqflite
+ sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ sqflite_android:
+ dependency: transitive
+ description:
+ name: sqflite_android
+ sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqflite_common:
+ dependency: transitive
+ description:
+ name: sqflite_common
+ sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.4+6"
+ sqflite_common_ffi:
+ dependency: "direct main"
+ description:
+ name: sqflite_common_ffi
+ sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4+4"
+ sqflite_darwin:
+ dependency: transitive
+ description:
+ name: sqflite_darwin
+ sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1+1"
+ sqflite_platform_interface:
+ dependency: transitive
+ description:
+ name: sqflite_platform_interface
+ sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqlite3:
+ dependency: transitive
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
stack_trace:
dependency: transitive
description:
@@ -706,6 +762,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml
index ed1f90c..7c963f2 100644
--- a/cw_core/pubspec.yaml
+++ b/cw_core/pubspec.yaml
@@ -14,7 +14,7 @@ dependencies:
sdk: flutter
http: ^1.1.0
file: ^7.0.0
- path_provider: ^2.0.11
+ path_provider: ^2.1.5
mobx: ^2.0.7+4
flutter_mobx: ^2.0.6+1
intl: any
@@ -44,6 +44,8 @@ dependencies:
git:
url: https://github.com/cake-tech/blockchain_utils
ref: cake-update-v2
+ sqflite: ^2.4.1
+ sqflite_common_ffi: ^2.3.4+4
dev_dependencies:
flutter_test:
diff --git a/cw_decred/lib/wallet.dart b/cw_decred/lib/wallet.dart
index fb177f4..432edb4 100644
--- a/cw_decred/lib/wallet.dart
+++ b/cw_decred/lib/wallet.dart
@@ -37,7 +37,7 @@ class DecredWallet = DecredWalletBase with _$DecredWallet;
abstract class DecredWalletBase
extends WalletBase<DecredBalance, DecredTransactionHistory, DecredTransactionInfo> with Store {
- DecredWalletBase(WalletInfo walletInfo, String password, Box<UnspentCoinsInfo> unspentCoinsInfo,
+ DecredWalletBase(WalletInfo walletInfo, DerivationInfo derivationInfo, String password, Box<UnspentCoinsInfo> unspentCoinsInfo,
Libwallet libwallet, Function() closeLibwallet)
: _password = password,
_libwallet = libwallet,
@@ -45,15 +45,15 @@ abstract class DecredWalletBase
this.syncStatus = NotConnectedSyncStatus(),
this.unspentCoinsInfo = unspentCoinsInfo,
this.watchingOnly =
- walletInfo.derivationInfo?.derivationPath == DecredWalletService.pubkeyRestorePath ||
- walletInfo.derivationInfo?.derivationPath ==
+ derivationInfo.derivationPath == DecredWalletService.pubkeyRestorePath ||
+ derivationInfo.derivationPath ==
DecredWalletService.pubkeyRestorePathTestnet,
this.balance = ObservableMap.of({CryptoCurrency.dcr: DecredBalance.zero()}),
- this.isTestnet = walletInfo.derivationInfo?.derivationPath ==
+ this.isTestnet = derivationInfo.derivationPath ==
DecredWalletService.seedRestorePathTestnet ||
- walletInfo.derivationInfo?.derivationPath ==
+ derivationInfo.derivationPath ==
DecredWalletService.pubkeyRestorePathTestnet,
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
walletAddresses = DecredWalletAddresses(walletInfo, libwallet);
transactionHistory = DecredTransactionHistory();
diff --git a/cw_decred/lib/wallet_addresses.dart b/cw_decred/lib/wallet_addresses.dart
index 860a576..e4af108 100644
--- a/cw_decred/lib/wallet_addresses.dart
+++ b/cw_decred/lib/wallet_addresses.dart
@@ -37,15 +37,11 @@ abstract class DecredWalletAddressesBase extends WalletAddresses with Store {
@override
Future<void> init() async {
- if (walletInfo.addresses != null) {
- addressesMap = walletInfo.addresses!;
- }
- if (walletInfo.addressInfos != null) {
- addressInfos = walletInfo.addressInfos!;
- }
- if (walletInfo.usedAddresses != null) {
- usedAddresses = {...walletInfo.usedAddresses!};
- }
+ addressesMap = await walletInfo.getAddresses();
+ addressInfos = await walletInfo.getAddressInfos();
+ usedAddresses = await walletInfo.getUsedAddresses();
+ manualAddresses = await walletInfo.getManualAddresses();
+ hiddenAddresses = await walletInfo.getHiddenAddresses();
await updateAddressesInBox();
}
@@ -61,7 +57,15 @@ abstract class DecredWalletAddressesBase extends WalletAddresses with Store {
}
addressesMap[addr] = "";
addressInfos[0] ??= [];
- addressInfos[0]?.add(AddressInfo(address: addr, label: "", accountIndex: 0));
+ addressInfos[0]?.add(
+ WalletInfoAddressInfo(
+ walletInfoId: walletInfo.internalId,
+ mapKey: 0,
+ address: addr,
+ label: "",
+ accountIndex: 0,
+ ),
+ );
});
// Add used addresses.
@@ -79,11 +83,11 @@ abstract class DecredWalletAddressesBase extends WalletAddresses with Store {
await saveAddressesInBox();
}
- List<AddressInfo> getAddressInfos() {
+ List<WalletInfoAddressInfo> getAddressInfos() {
if (addressInfos.containsKey(0)) {
return addressInfos[0]!;
}
- return <AddressInfo>[];
+ return <WalletInfoAddressInfo>[];
}
Future<void> updateAddress(String address, String label) async {
@@ -128,7 +132,15 @@ abstract class DecredWalletAddressesBase extends WalletAddresses with Store {
if (!addressesMap.containsKey(addr)) {
addressesMap[addr] = "";
addressInfos[0] ??= [];
- addressInfos[0]?.add(AddressInfo(address: addr, label: label, accountIndex: 0));
+ addressInfos[0]?.add(
+ WalletInfoAddressInfo(
+ walletInfoId: walletInfo.internalId,
+ mapKey: 0,
+ address: addr,
+ label: label,
+ accountIndex: 0,
+ ),
+ );
}
selectedAddr = addr;
await saveAddressesInBox();
diff --git a/cw_decred/lib/wallet_service.dart b/cw_decred/lib/wallet_service.dart
index 93c7088..afcf6d5 100644
--- a/cw_decred/lib/wallet_service.dart
+++ b/cw_decred/lib/wallet_service.dart
@@ -18,9 +18,8 @@ class DecredWalletService extends WalletService<
DecredRestoreWalletFromSeedCredentials,
DecredRestoreWalletFromPubkeyCredentials,
DecredRestoreWalletFromHardwareCredentials> {
- DecredWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
+ DecredWalletService(this.unspentCoinsInfoSource);
- final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final seedRestorePath = "m/44'/42'";
static final seedRestorePathTestnet = "m/44'/1'";
@@ -68,9 +67,10 @@ class DecredWalletService extends WalletService<
"unsyncedaddrs": true,
};
await libwallet!.createWallet(jsonEncode(config));
- final di = DerivationInfo(
- derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
- credentials.walletInfo!.derivationInfo = di;
+ final di = await credentials.walletInfo!.getDerivationInfo();
+ di.derivationPath = isTestnet == true ? seedRestorePathTestnet : seedRestorePath;
+ await di.save();
+ credentials.walletInfo!.save();
credentials.walletInfo!.network = network;
// ios will move our wallet directory when updating. Since we must
// recalculate the new path every time we open the wallet, ensure this path
@@ -79,7 +79,7 @@ class DecredWalletService extends WalletService<
// going forward.
credentials.walletInfo!.dirPath = "";
credentials.walletInfo!.path = "";
- final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
+ final wallet = DecredWallet(credentials.walletInfo!, di, credentials.password!,
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
@@ -113,13 +113,17 @@ class DecredWalletService extends WalletService<
@override
Future<DecredWallet> openWallet(String name, String password) async {
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ final di = await walletInfo.getDerivationInfo();
if (walletInfo.network == null || walletInfo.network == "") {
- walletInfo.network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
- walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
+ walletInfo.network = di.derivationPath == seedRestorePathTestnet ||
+ di.derivationPath == pubkeyRestorePathTestnet
? testnet
: mainnet;
+ walletInfo.save();
}
await this.init();
@@ -149,7 +153,7 @@ class DecredWalletService extends WalletService<
};
await libwallet!.loadWallet(jsonEncode(config));
final wallet =
- DecredWallet(walletInfo, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
+ DecredWallet(walletInfo, di, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
}
@@ -157,25 +161,32 @@ class DecredWalletService extends WalletService<
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
- final network = currentWalletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
- currentWalletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ final di = await currentWalletInfo.getDerivationInfo();
+ final network = di.derivationPath == seedRestorePathTestnet ||
+ di.derivationPath == pubkeyRestorePathTestnet
? testnet
: mainnet;
+ currentWalletInfo.network = network;
+ currentWalletInfo.save();
if (libwallet == null) {
libwallet = await Libwallet.spawn();
libwallet!.initLibdcrwallet("", "err");
}
final currentWallet = DecredWallet(
- currentWalletInfo, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
+ currentWalletInfo, di, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await currentWallet.renameWalletFiles(newName);
@@ -185,7 +196,7 @@ class DecredWalletService extends WalletService<
newWalletInfo.dirPath = "";
newWalletInfo.path = "";
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -203,13 +214,13 @@ class DecredWalletService extends WalletService<
"unsyncedaddrs": true,
};
await libwallet!.createWallet(jsonEncode(config));
- final di = DerivationInfo(
- derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
- credentials.walletInfo!.derivationInfo = di;
+ final di = await credentials.walletInfo!.getDerivationInfo();
+ di.derivationPath = isTestnet == true ? seedRestorePathTestnet : seedRestorePath;
+ await di.save();
credentials.walletInfo!.network = network;
credentials.walletInfo!.dirPath = "";
credentials.walletInfo!.path = "";
- final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
+ final wallet = DecredWallet(credentials.walletInfo!, di, credentials.password!,
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
@@ -231,13 +242,13 @@ class DecredWalletService extends WalletService<
"unsyncedaddrs": true,
};
await libwallet!.createWatchOnlyWallet(jsonEncode(config));
- final di = DerivationInfo(
- derivationPath: isTestnet == true ? pubkeyRestorePathTestnet : pubkeyRestorePath);
- credentials.walletInfo!.derivationInfo = di;
+ final di = await credentials.walletInfo!.getDerivationInfo();
+ di.derivationPath = isTestnet == true ? pubkeyRestorePathTestnet : pubkeyRestorePath;
+ await di.save();
credentials.walletInfo!.network = network;
credentials.walletInfo!.dirPath = "";
credentials.walletInfo!.path = "";
- final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
+ final wallet = DecredWallet(credentials.walletInfo!, di, credentials.password!,
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
await wallet.init();
return wallet;
diff --git a/cw_decred/pubspec.lock b/cw_decred/pubspec.lock
index 83fc4d2..8558572 100644
--- a/cw_decred/pubspec.lock
+++ b/cw_decred/pubspec.lock
@@ -705,6 +705,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
+ sqflite:
+ dependency: transitive
+ description:
+ name: sqflite
+ sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ sqflite_android:
+ dependency: transitive
+ description:
+ name: sqflite_android
+ sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqflite_common:
+ dependency: transitive
+ description:
+ name: sqflite_common
+ sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.4+6"
+ sqflite_common_ffi:
+ dependency: transitive
+ description:
+ name: sqflite_common_ffi
+ sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4+4"
+ sqflite_darwin:
+ dependency: transitive
+ description:
+ name: sqflite_darwin
+ sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1+1"
+ sqflite_platform_interface:
+ dependency: transitive
+ description:
+ name: sqflite_platform_interface
+ sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqlite3:
+ dependency: transitive
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
stack_trace:
dependency: transitive
description:
@@ -737,6 +793,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
diff --git a/cw_dogecoin/lib/src/dogecoin_wallet.dart b/cw_dogecoin/lib/src/dogecoin_wallet.dart
index 7e0b61a..964c34b 100644
--- a/cw_dogecoin/lib/src/dogecoin_wallet.dart
+++ b/cw_dogecoin/lib/src/dogecoin_wallet.dart
@@ -26,6 +26,7 @@ abstract class DogeCoinWalletBase extends ElectrumWallet with Store {
required String mnemonic,
required String password,
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
@@ -39,6 +40,7 @@ abstract class DogeCoinWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
network: DogecoinNetwork.mainnet,
initialAddresses: initialAddresses,
@@ -83,6 +85,7 @@ abstract class DogeCoinWalletBase extends ElectrumWallet with Store {
{required String mnemonic,
required String password,
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required EncryptionFileUtils encryptionFileUtils,
String? passphrase,
@@ -95,6 +98,7 @@ abstract class DogeCoinWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
@@ -148,6 +152,7 @@ abstract class DogeCoinWalletBase extends ElectrumWallet with Store {
mnemonic: keysData.mnemonic!,
password: password,
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp?.addresses,
initialBalance: snp?.balance,
diff --git a/cw_dogecoin/lib/src/dogecoin_wallet_service.dart b/cw_dogecoin/lib/src/dogecoin_wallet_service.dart
index d0e3b29..988abd2 100644
--- a/cw_dogecoin/lib/src/dogecoin_wallet_service.dart
+++ b/cw_dogecoin/lib/src/dogecoin_wallet_service.dart
@@ -18,9 +18,8 @@ class DogeCoinWalletService extends WalletService<
DogeCoinRestoreWalletFromSeedCredentials,
DogeCoinRestoreWalletFromWIFCredentials,
DogeCoinNewWalletCredentials> {
- DogeCoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
+ DogeCoinWalletService(this.unspentCoinsInfoSource, this.isDirect);
- final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final bool isDirect;
@@ -39,6 +38,7 @@ class DogeCoinWalletService extends WalletService<
mnemonic: credentials.mnemonic ?? MnemonicBip39.generate(strength: strength),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
passphrase: credentials.passphrase,
@@ -51,9 +51,10 @@ class DogeCoinWalletService extends WalletService<
@override
Future<DogeCoinWallet> openWallet(String name, String password) async {
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
-
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await DogeCoinWalletBase.open(
password: password,
@@ -82,9 +83,11 @@ class DogeCoinWalletService extends WalletService<
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
final unspentCoinsToDelete = unspentCoinsInfoSource.values
.where((unspentCoin) => unspentCoin.walletId == walletInfo.id)
@@ -99,8 +102,10 @@ class DogeCoinWalletService extends WalletService<
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await DogeCoinWalletBase.open(
password: password,
name: currentName,
@@ -115,7 +120,7 @@ class DogeCoinWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -141,6 +146,7 @@ class DogeCoinWalletService extends WalletService<
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
passphrase: credentials.passphrase);
diff --git a/cw_ethereum/lib/ethereum_wallet.dart b/cw_ethereum/lib/ethereum_wallet.dart
index 48cd678..edf1011 100644
--- a/cw_ethereum/lib/ethereum_wallet.dart
+++ b/cw_ethereum/lib/ethereum_wallet.dart
@@ -23,6 +23,7 @@ class EthereumWallet extends EVMChainWallet {
required super.client,
required super.password,
required super.walletInfo,
+ required super.derivationInfo,
super.mnemonic,
super.initialBalance,
super.privateKey,
@@ -176,6 +177,7 @@ class EthereumWallet extends EVMChainWallet {
return EthereumWallet(
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
password: password,
mnemonic: keysData.mnemonic,
privateKey: keysData.privateKey,
diff --git a/cw_ethereum/lib/ethereum_wallet_service.dart b/cw_ethereum/lib/ethereum_wallet_service.dart
index d208fdc..1976c27 100644
--- a/cw_ethereum/lib/ethereum_wallet_service.dart
+++ b/cw_ethereum/lib/ethereum_wallet_service.dart
@@ -10,7 +10,7 @@ import 'package:cw_evm/evm_chain_wallet_creation_credentials.dart';
import 'package:cw_evm/evm_chain_wallet_service.dart';
class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
- EthereumWalletService(super.walletInfoSource, super.isDirect, {required this.client});
+ EthereumWalletService(super.isDirect, {required this.client});
late EthereumClient client;
@@ -25,6 +25,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
final wallet = EthereumWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
mnemonic: mnemonic,
password: credentials.password!,
passphrase: credentials.passphrase,
@@ -41,8 +42,10 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
@override
Future<EthereumWallet> openWallet(String name, String password) async {
- final walletInfo =
- walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await EthereumWallet.open(
@@ -75,8 +78,10 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await EthereumWallet.open(
password: password,
name: currentName,
@@ -91,21 +96,23 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
Future<EthereumWallet> restoreFromHardwareWallet(
EVMChainRestoreWalletFromHardware credentials) async {
- credentials.walletInfo!.derivationInfo = DerivationInfo(
- derivationType: DerivationType.bip39,
- derivationPath: "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0"
- );
+ final di = await credentials.walletInfo!.getDerivationInfo();
+ di.derivationType = DerivationType.bip39;
+ di.derivationPath = "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0";
+ await di.save();
credentials.walletInfo!.hardwareWalletType = credentials.hardwareWalletType;
credentials.walletInfo!.address = credentials.hwAccountData.address;
+ credentials.walletInfo!.save();
final wallet = EthereumWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: di,
password: credentials.password!,
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -125,6 +132,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
password: credentials.password!,
privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -147,6 +155,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
passphrase: credentials.passphrase,
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart
index 3bf066c..e1058da 100644
--- a/cw_evm/lib/evm_chain_wallet.dart
+++ b/cw_evm/lib/evm_chain_wallet.dart
@@ -67,6 +67,7 @@ abstract class EVMChainWalletBase
with Store, WalletKeysFile {
EVMChainWalletBase({
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required EVMChainClient client,
required CryptoCurrency nativeCurrency,
String? mnemonic,
@@ -88,7 +89,7 @@ abstract class EVMChainWalletBase
nativeCurrency: initialBalance ?? EVMChainERC20Balance(BigInt.zero),
},
),
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
this.walletInfo = walletInfo;
transactionHistory = setUpTransactionHistory(walletInfo, password, encryptionFileUtils);
diff --git a/cw_evm/lib/evm_chain_wallet_service.dart b/cw_evm/lib/evm_chain_wallet_service.dart
index e6bb41b..ea6e68a 100644
--- a/cw_evm/lib/evm_chain_wallet_service.dart
+++ b/cw_evm/lib/evm_chain_wallet_service.dart
@@ -15,9 +15,8 @@ abstract class EVMChainWalletService<T extends EVMChainWallet> extends WalletSer
EVMChainRestoreWalletFromSeedCredentials,
EVMChainRestoreWalletFromPrivateKey,
EVMChainRestoreWalletFromHardware> {
- EVMChainWalletService(this.walletInfoSource, this.isDirect);
+ EVMChainWalletService(this.isDirect);
- final Box<WalletInfo> walletInfoSource;
final bool isDirect;
@override
@@ -48,8 +47,10 @@ abstract class EVMChainWalletService<T extends EVMChainWallet> extends WalletSer
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
}
diff --git a/cw_evm/lib/hardware/evm_chain_ledger_credentials.dart b/cw_evm/lib/hardware/evm_chain_ledger_credentials.dart
index 13a93cf..fdf7a5c 100644
--- a/cw_evm/lib/hardware/evm_chain_ledger_credentials.dart
+++ b/cw_evm/lib/hardware/evm_chain_ledger_credentials.dart
@@ -19,8 +19,8 @@ class EvmLedgerCredentials extends CredentialsWithKnownAddress {
@override
EthereumAddress get address => EthereumAddress.fromHex(_address);
- void setLedgerConnection(LedgerConnection connection,
- [String? derivationPath]) {
+ Future<void> setLedgerConnection(LedgerConnection connection,
+ [String? derivationPath]) async {
ethereumLedgerApp = EthereumLedgerApp(connection,
derivationPath: derivationPath ?? "m/44'/60'/0'/0/0");
}
diff --git a/cw_monero/lib/ledger.dart b/cw_monero/lib/ledger.dart
index 7a3c95a..7707acd 100644
--- a/cw_monero/lib/ledger.dart
+++ b/cw_monero/lib/ledger.dart
@@ -15,7 +15,7 @@ String? latestLedgerCommand;
typedef LedgerCallback = Void Function(Pointer<UnsignedChar>, UnsignedInt);
NativeCallable<LedgerCallback>? callable;
-void enableLedgerExchange(LedgerConnection connection) {
+Future<void> enableLedgerExchange(LedgerConnection connection) async {
callable?.close();
void callback(Pointer<UnsignedChar> request, int requestLength) async {
diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart
index 57cc9a3..9f5986e 100644
--- a/cw_monero/lib/monero_wallet.dart
+++ b/cw_monero/lib/monero_wallet.dart
@@ -55,6 +55,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
MoneroWalletBase(
{required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required String password})
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
@@ -70,7 +71,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
syncStatus = NotConnectedSyncStatus(),
unspentCoins = [],
this.unspentCoinsInfo = unspentCoinsInfo,
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
transactionHistory = MoneroTransactionHistory();
walletAddresses = MoneroWalletAddresses(walletInfo, transactionHistory);
@@ -976,8 +977,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
return monero_wallet.verifyMessage(message, address, signature);
}
- void setLedgerConnection(LedgerConnection connection) {
- enableLedgerExchange(connection);
+ Future<void> setLedgerConnection(LedgerConnection connection) async {
+ await enableLedgerExchange(connection);
}
@override
diff --git a/cw_monero/lib/monero_wallet_addresses.dart b/cw_monero/lib/monero_wallet_addresses.dart
index d0cf874..0b38ac5 100644
--- a/cw_monero/lib/monero_wallet_addresses.dart
+++ b/cw_monero/lib/monero_wallet_addresses.dart
@@ -5,7 +5,6 @@ import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
-import 'package:cw_monero/api/transaction_history.dart';
import 'package:cw_monero/api/wallet.dart';
import 'package:cw_monero/monero_account_list.dart';
import 'package:cw_monero/monero_subaddress_list.dart';
@@ -90,8 +89,12 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
_subaddressList.subaddresses.forEach((subaddress) {
addressesMap[subaddress.address] = subaddress.label;
addressInfos[account.id] ??= [];
- addressInfos[account.id]?.add(AddressInfo(
- address: subaddress.address, label: subaddress.label, accountIndex: account.id));
+ addressInfos[account.id]?.add(WalletInfoAddressInfo(
+ walletInfoId: walletInfo.internalId,
+ mapKey: account.id,
+ accountIndex: account.id,
+ address: subaddress.address,
+ label: subaddress.label));
});
});
diff --git a/cw_monero/lib/monero_wallet_service.dart b/cw_monero/lib/monero_wallet_service.dart
index 6fc8270..f383419 100644
--- a/cw_monero/lib/monero_wallet_service.dart
+++ b/cw_monero/lib/monero_wallet_service.dart
@@ -99,9 +99,8 @@ class MoneroWalletService extends WalletService<
MoneroRestoreWalletFromSeedCredentials,
MoneroRestoreWalletFromKeysCredentials,
MoneroRestoreWalletFromHardwareCredentials> {
- MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
+ MoneroWalletService(this.unspentCoinsInfoSource);
- final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
static bool walletFilesExist(String path) =>
@@ -148,6 +147,7 @@ class MoneroWalletService extends WalletService<
passphrase: credentials.passphrase ?? "");
final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: credentials.password!);
await wallet.init();
@@ -182,10 +182,13 @@ class MoneroWalletService extends WalletService<
await monero_wallet_manager
.openWallet(path: path, password: password);
- final walletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final wallet = MoneroWallet(
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: password);
@@ -234,17 +237,22 @@ class MoneroWalletService extends WalletService<
await file.delete(recursive: true);
}
- final walletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values.firstWhere(
- (info) => info.id == WalletBase.idFor(currentName, getType()));
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = MoneroWallet(
walletInfo: currentWalletInfo,
+ derivationInfo: await currentWalletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
);
@@ -255,7 +263,7 @@ class MoneroWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -273,6 +281,7 @@ class MoneroWalletService extends WalletService<
spendKey: credentials.spendKey);
final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: credentials.password!);
await wallet.init();
@@ -303,6 +312,7 @@ class MoneroWalletService extends WalletService<
final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: credentials.password!);
await wallet.init();
@@ -359,6 +369,7 @@ class MoneroWalletService extends WalletService<
restoreHeight: credentials.height!);
final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: credentials.password!);
await wallet.init();
@@ -379,10 +390,11 @@ class MoneroWalletService extends WalletService<
String? passphrase,
int? overrideHeight,
}) async {
- walletInfo.derivationInfo = DerivationInfo(
- derivationType: DerivationType.bip39,
- derivationPath: "m/44'/128'/0'/0/0",
- );
+ final derivationInfo = await walletInfo.getDerivationInfo();
+ derivationInfo.derivationType = DerivationType.bip39;
+ derivationInfo.derivationPath = "m/44'/128'/0'/0/0";
+ await derivationInfo.save();
+ walletInfo.save();
final legacyMnemonic =
getLegacySeedFromBip39(mnemonic, passphrase: passphrase ?? "");
@@ -409,6 +421,7 @@ class MoneroWalletService extends WalletService<
final wallet = MoneroWallet(
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
);
@@ -453,6 +466,7 @@ class MoneroWalletService extends WalletService<
final wallet = MoneroWallet(
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
);
@@ -485,6 +499,7 @@ class MoneroWalletService extends WalletService<
final wallet = MoneroWallet(
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
);
@@ -529,10 +544,13 @@ class MoneroWalletService extends WalletService<
await monero_wallet_manager
.openWallet(path: path, password: password);
- final walletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final wallet = MoneroWallet(
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
);
@@ -544,12 +562,12 @@ class MoneroWalletService extends WalletService<
}
@override
- bool requireHardwareWalletConnection(String name) {
- return walletInfoSource.values
- .firstWhereOrNull(
- (info) => info.id == WalletBase.idFor(name, getType()))
- ?.isHardwareWallet ??
- false;
+ Future<bool> requireHardwareWalletConnection(String name) async {
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ return walletInfo.isHardwareWallet;
}
}
diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock
index 23944e4..ae521ab 100644
--- a/cw_monero/pubspec.lock
+++ b/cw_monero/pubspec.lock
@@ -818,6 +818,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
+ sqflite:
+ dependency: transitive
+ description:
+ name: sqflite
+ sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ sqflite_android:
+ dependency: transitive
+ description:
+ name: sqflite_android
+ sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqflite_common:
+ dependency: transitive
+ description:
+ name: sqflite_common
+ sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.4+6"
+ sqflite_common_ffi:
+ dependency: "direct dev"
+ description:
+ name: sqflite_common_ffi
+ sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4+4"
+ sqflite_darwin:
+ dependency: transitive
+ description:
+ name: sqflite_darwin
+ sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1+1"
+ sqflite_platform_interface:
+ dependency: transitive
+ description:
+ name: sqflite_platform_interface
+ sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqlite3:
+ dependency: transitive
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
stack_trace:
dependency: transitive
description:
@@ -850,6 +906,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml
index 1eb8155..3877032 100644
--- a/cw_monero/pubspec.yaml
+++ b/cw_monero/pubspec.yaml
@@ -39,6 +39,7 @@ dev_dependencies:
mobx_codegen: ^2.0.7
mockito: ^5.4.5
hive_generator: ^2.0.1
+ sqflite_common_ffi: ^2.3.4+4
dependency_overrides:
watcher: ^1.1.0
diff --git a/cw_monero/test/monero_wallet_service_test.dart b/cw_monero/test/monero_wallet_service_test.dart
index a809dbc..3b24c20 100644
--- a/cw_monero/test/monero_wallet_service_test.dart
+++ b/cw_monero/test/monero_wallet_service_test.dart
@@ -1,5 +1,6 @@
import 'dart:io';
+import 'package:cw_core/db/sqlite.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
@@ -7,26 +8,28 @@ import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/monero_wallet_service.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
+import 'package:sqflite/sqflite.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
+import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'mock/path_provider.dart';
import 'utils/setup_monero_c.dart';
Future<void> main() async {
group("MoneroWalletService Tests", () {
- Hive.init('./test/data/db');
late MoneroWalletService walletService;
late File moneroCBinary;
setUpAll(() async {
+ databaseFactory = databaseFactoryFfi;
+ await initDb(pathOverride: './test/data/db');
+ Hive.init('./test/data/db');
PathProviderPlatform.instance = MockPathProviderPlatform();
- final Box<WalletInfo> walletInfoSource =
- await Hive.openBox('testWalletInfo');
final Box<UnspentCoinsInfo> unspentCoinsInfoSource =
await Hive.openBox('testUnspentCoinsInfo');
- walletService = MoneroWalletService(walletInfoSource, unspentCoinsInfoSource);
+ walletService = MoneroWalletService(unspentCoinsInfoSource);
moneroCBinary = getMoneroCBinary().copySync(moneroCBinaryName);
});
diff --git a/cw_nano/lib/nano_wallet.dart b/cw_nano/lib/nano_wallet.dart
index cab0292..2cf7fd3 100644
--- a/cw_nano/lib/nano_wallet.dart
+++ b/cw_nano/lib/nano_wallet.dart
@@ -39,6 +39,7 @@ abstract class NanoWalletBase
with Store, WalletKeysFile {
NanoWalletBase({
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
required String mnemonic,
required String password,
NanoBalance? initialBalance,
@@ -47,7 +48,7 @@ abstract class NanoWalletBase
}) : syncStatus = NotConnectedSyncStatus(),
_password = password,
_mnemonic = mnemonic,
- _derivationType = walletInfo.derivationInfo!.derivationType!,
+ _derivationType = derivationInfo.derivationType!,
_isTransactionUpdating = false,
_encryptionFileUtils = encryptionFileUtils,
_client = NanoClient(),
@@ -56,7 +57,7 @@ abstract class NanoWalletBase
CryptoCurrency.nano: initialBalance ??
NanoBalance(currentBalance: BigInt.zero, receivableBalance: BigInt.zero)
}),
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
this.walletInfo = walletInfo;
transactionHistory = NanoTransactionHistory(
walletInfo: walletInfo,
@@ -433,11 +434,13 @@ abstract class NanoWalletBase
derivationType = DerivationType.bip39;
}
- walletInfo.derivationInfo ??= DerivationInfo(derivationType: derivationType);
- walletInfo.derivationInfo!.derivationType ??= derivationType;
+ final derivationInfo = await walletInfo.getDerivationInfo();
+ derivationInfo.derivationType ??= derivationType;
+ derivationInfo.save();
return NanoWallet(
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
password: password,
mnemonic: keysData.mnemonic!,
initialBalance: balance,
diff --git a/cw_nano/lib/nano_wallet_creation_credentials.dart b/cw_nano/lib/nano_wallet_creation_credentials.dart
index 8eb6dc2..d2a8db7 100644
--- a/cw_nano/lib/nano_wallet_creation_credentials.dart
+++ b/cw_nano/lib/nano_wallet_creation_credentials.dart
@@ -14,6 +14,7 @@ class NanoNewWalletCredentials extends WalletCredentials {
password: password,
walletInfo: walletInfo,
passphrase: passphrase,
+ derivationInfo: DerivationInfo(derivationType: derivationType),
);
final String? mnemonic;
diff --git a/cw_nano/lib/nano_wallet_service.dart b/cw_nano/lib/nano_wallet_service.dart
index 5c073c9..0dd5792 100644
--- a/cw_nano/lib/nano_wallet_service.dart
+++ b/cw_nano/lib/nano_wallet_service.dart
@@ -19,9 +19,8 @@ class NanoWalletService extends WalletService<
NanoRestoreWalletFromSeedCredentials,
NanoRestoreWalletFromKeysCredentials,
NanoNewWalletCredentials> {
- NanoWalletService(this.walletInfoSource, this.isDirect);
+ NanoWalletService(this.isDirect);
- final Box<WalletInfo> walletInfoSource;
final bool isDirect;
static bool walletFilesExist(String path) =>
@@ -33,7 +32,8 @@ class NanoWalletService extends WalletService<
@override
Future<WalletBase> create(NanoNewWalletCredentials credentials, {bool? isTestnet}) async {
final String mnemonic;
- switch (credentials.walletInfo?.derivationInfo?.derivationType) {
+ final derivationInfo = credentials.derivationInfo ?? await credentials.walletInfo!.getDerivationInfo();
+ switch (derivationInfo.derivationType) {
case DerivationType.nano:
String seedKey = NanoSeeds.generateSeed();
mnemonic = credentials.mnemonic ?? NanoDerivations.standardSeedToMnemonic(seedKey);
@@ -47,6 +47,7 @@ class NanoWalletService extends WalletService<
final wallet = NanoWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: derivationInfo,
mnemonic: mnemonic,
password: credentials.password!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -65,20 +66,25 @@ class NanoWalletService extends WalletService<
await file.delete(recursive: true);
}
- final walletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
String randomWords =
(List<String>.from(nm.NanoMnemomics.WORDLIST)..shuffle()).take(24).join(' ');
final currentWallet = NanoWallet(
walletInfo: currentWalletInfo,
+ derivationInfo: await currentWalletInfo.getDerivationInfo(),
password: password,
mnemonic: randomWords,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -91,7 +97,7 @@ class NanoWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -115,18 +121,17 @@ class NanoWalletService extends WalletService<
throw Exception("Wasn't a valid nano style seed!");
}
}
-
+ final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
// should never happen but just in case:
- if (credentials.walletInfo!.derivationInfo == null) {
- credentials.walletInfo!.derivationInfo = DerivationInfo(derivationType: DerivationType.nano);
- } else if (credentials.walletInfo!.derivationInfo!.derivationType == null) {
- credentials.walletInfo!.derivationInfo!.derivationType = DerivationType.nano;
+ if (derivationInfo.derivationType == null) {
+ derivationInfo.derivationType = DerivationType.nano;
}
final wallet = await NanoWallet(
password: credentials.password!,
mnemonic: mnemonic ?? credentials.seedKey,
walletInfo: credentials.walletInfo!,
+ derivationInfo: derivationInfo,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
await wallet.init();
@@ -157,15 +162,17 @@ class NanoWalletService extends WalletService<
}
}
- DerivationType derivationType =
- credentials.walletInfo?.derivationInfo?.derivationType ?? DerivationType.nano;
+ final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
+ DerivationType derivationType = derivationInfo.derivationType ?? DerivationType.nano;
- credentials.walletInfo!.derivationInfo ??= DerivationInfo(derivationType: derivationType);
+ derivationInfo.derivationType = derivationType;
+ derivationInfo.save();
final wallet = await NanoWallet(
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: derivationInfo,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -180,8 +187,10 @@ class NanoWalletService extends WalletService<
@override
Future<NanoWallet> openWallet(String name, String password) async {
- final walletInfo =
- walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await NanoWalletBase.open(
diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock
index b14c7bd..c009b65 100644
--- a/cw_nano/pubspec.lock
+++ b/cw_nano/pubspec.lock
@@ -823,6 +823,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
+ sqflite:
+ dependency: transitive
+ description:
+ name: sqflite
+ sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ sqflite_android:
+ dependency: transitive
+ description:
+ name: sqflite_android
+ sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqflite_common:
+ dependency: transitive
+ description:
+ name: sqflite_common
+ sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.4+6"
+ sqflite_common_ffi:
+ dependency: transitive
+ description:
+ name: sqflite_common_ffi
+ sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4+4"
+ sqflite_darwin:
+ dependency: transitive
+ description:
+ name: sqflite_darwin
+ sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1+1"
+ sqflite_platform_interface:
+ dependency: transitive
+ description:
+ name: sqflite_platform_interface
+ sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqlite3:
+ dependency: transitive
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
stack_trace:
dependency: transitive
description:
@@ -855,6 +911,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
diff --git a/cw_polygon/lib/polygon_wallet.dart b/cw_polygon/lib/polygon_wallet.dart
index ed0e54e..5b58799 100644
--- a/cw_polygon/lib/polygon_wallet.dart
+++ b/cw_polygon/lib/polygon_wallet.dart
@@ -21,6 +21,7 @@ import 'package:cw_polygon/polygon_transaction_info.dart';
class PolygonWallet extends EVMChainWallet {
PolygonWallet({
required super.walletInfo,
+ required super.derivationInfo,
required super.password,
super.mnemonic,
super.initialBalance,
@@ -152,8 +153,11 @@ class PolygonWallet extends EVMChainWallet {
);
}
+ final derivationInfo = await walletInfo.getDerivationInfo();
+
return PolygonWallet(
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
password: password,
mnemonic: keysData.mnemonic,
privateKey: keysData.privateKey,
diff --git a/cw_polygon/lib/polygon_wallet_service.dart b/cw_polygon/lib/polygon_wallet_service.dart
index ece7a6b..23a31ec 100644
--- a/cw_polygon/lib/polygon_wallet_service.dart
+++ b/cw_polygon/lib/polygon_wallet_service.dart
@@ -10,8 +10,7 @@ import 'package:cw_polygon/polygon_mnemonics_exception.dart';
import 'package:cw_polygon/polygon_wallet.dart';
class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
- PolygonWalletService(
- super.walletInfoSource, super.isDirect, {
+ PolygonWalletService(super.isDirect, {
required this.client,
});
@@ -28,6 +27,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
final wallet = PolygonWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
mnemonic: mnemonic,
password: credentials.password!,
passphrase: credentials.passphrase,
@@ -43,8 +43,10 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
@override
Future<PolygonWallet> openWallet(String name, String password) async {
- final walletInfo =
- walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await PolygonWallet.open(
@@ -82,6 +84,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
password: credentials.password!,
privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -95,15 +98,16 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
@override
Future<PolygonWallet> restoreFromHardwareWallet(
EVMChainRestoreWalletFromHardware credentials) async {
- credentials.walletInfo!.derivationInfo = DerivationInfo(
- derivationType: DerivationType.bip39,
- derivationPath: "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0"
- );
+ final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
+ derivationInfo.derivationType = DerivationType.bip39;
+ derivationInfo.derivationPath = "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0";
+ derivationInfo.save();
credentials.walletInfo!.hardwareWalletType = credentials.hardwareWalletType;
credentials.walletInfo!.address = credentials.hwAccountData.address;
final wallet = PolygonWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: derivationInfo,
password: credentials.password!,
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -127,6 +131,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
passphrase: credentials.passphrase,
client: client,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -141,8 +146,10 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await PolygonWallet.open(
password: password,
name: currentName,
@@ -157,6 +164,6 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
}
diff --git a/cw_shared_external/lib/cw_shared_external.dart b/cw_shared_external/lib/cw_shared_external.dart
index 37d0350..1d9df69 100644
--- a/cw_shared_external/lib/cw_shared_external.dart
+++ b/cw_shared_external/lib/cw_shared_external.dart
@@ -8,7 +8,7 @@ class CwSharedExternal {
const MethodChannel('cw_shared_external');
static Future<String> get platformVersion async {
- final String version = await _channel.invokeMethod('getPlatformVersion');
+ final String version = (await _channel.invokeMethod('getPlatformVersion')).toString();
return version;
}
}
diff --git a/cw_solana/lib/solana_wallet.dart b/cw_solana/lib/solana_wallet.dart
index 581ba56..245f1e7 100644
--- a/cw_solana/lib/solana_wallet.dart
+++ b/cw_solana/lib/solana_wallet.dart
@@ -43,6 +43,7 @@ abstract class SolanaWalletBase
with Store, WalletKeysFile {
SolanaWalletBase({
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
String? mnemonic,
String? privateKey,
required String password,
@@ -57,7 +58,7 @@ abstract class SolanaWalletBase
walletAddresses = SolanaWalletAddresses(walletInfo),
balance = ObservableMap<CryptoCurrency, SolanaBalance>.of(
{CryptoCurrency.sol: initialBalance ?? SolanaBalance(BigInt.zero.toDouble())}),
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
this.walletInfo = walletInfo;
transactionHistory = SolanaTransactionHistory(
walletInfo: walletInfo,
@@ -449,8 +450,11 @@ abstract class SolanaWalletBase
);
}
+ final derivationInfo = await walletInfo.getDerivationInfo();
+
return SolanaWallet(
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
password: password,
passphrase: keysData.passphrase,
mnemonic: keysData.mnemonic,
diff --git a/cw_solana/lib/solana_wallet_service.dart b/cw_solana/lib/solana_wallet_service.dart
index faeb24a..a16f3ee 100644
--- a/cw_solana/lib/solana_wallet_service.dart
+++ b/cw_solana/lib/solana_wallet_service.dart
@@ -18,9 +18,8 @@ import 'package:hive/hive.dart';
class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
SolanaRestoreWalletFromSeedCredentials, SolanaRestoreWalletFromPrivateKey, SolanaNewWalletCredentials> {
- SolanaWalletService(this.walletInfoSource, this.isDirect);
+ SolanaWalletService(this.isDirect);
- final Box<WalletInfo> walletInfoSource;
final bool isDirect;
@override
@@ -31,6 +30,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
final wallet = SolanaWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
mnemonic: mnemonic,
password: credentials.password!,
passphrase: credentials.passphrase,
@@ -52,8 +52,10 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
@override
Future<SolanaWallet> openWallet(String name, String password) async {
- final walletInfo =
- walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await SolanaWalletBase.open(
@@ -88,9 +90,11 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
@@ -100,6 +104,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
password: credentials.password!,
privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -121,6 +126,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
passphrase: credentials.passphrase,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -134,8 +140,10 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await SolanaWalletBase.open(
password: password,
name: currentName,
@@ -150,7 +158,7 @@ class SolanaWalletService extends WalletService<SolanaNewWalletCredentials,
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
diff --git a/cw_tron/lib/tron_wallet.dart b/cw_tron/lib/tron_wallet.dart
index 6a6b55a..80afb2f 100644
--- a/cw_tron/lib/tron_wallet.dart
+++ b/cw_tron/lib/tron_wallet.dart
@@ -42,6 +42,7 @@ abstract class TronWalletBase
with Store, WalletKeysFile {
TronWalletBase({
required WalletInfo walletInfo,
+ required DerivationInfo derivationInfo,
String? mnemonic,
String? privateKey,
required String password,
@@ -57,7 +58,7 @@ abstract class TronWalletBase
balance = ObservableMap<CryptoCurrency, TronBalance>.of(
{CryptoCurrency.trx: initialBalance ?? TronBalance(BigInt.zero)},
),
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
this.walletInfo = walletInfo;
transactionHistory = TronTransactionHistory(
walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils);
@@ -163,8 +164,11 @@ abstract class TronWalletBase
);
}
+ final derivationInfo = await walletInfo.getDerivationInfo();
+
return TronWallet(
walletInfo: walletInfo,
+ derivationInfo: derivationInfo,
password: password,
mnemonic: keysData.mnemonic,
privateKey: keysData.privateKey,
diff --git a/cw_tron/lib/tron_wallet_service.dart b/cw_tron/lib/tron_wallet_service.dart
index 0c1ac60..cf83b91 100644
--- a/cw_tron/lib/tron_wallet_service.dart
+++ b/cw_tron/lib/tron_wallet_service.dart
@@ -1,7 +1,6 @@
import 'dart:io';
import 'package:bip39/bip39.dart' as bip39;
-import 'package:collection/collection.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/pathForWallet.dart';
@@ -22,11 +21,10 @@ class TronWalletService extends WalletService<
TronRestoreWalletFromSeedCredentials,
TronRestoreWalletFromPrivateKey,
TronNewWalletCredentials> {
- TronWalletService(this.walletInfoSource, {required this.client, required this.isDirect});
+ TronWalletService({required this.client, required this.isDirect});
late TronClient client;
- final Box<WalletInfo> walletInfoSource;
final bool isDirect;
@override
@@ -40,6 +38,7 @@ class TronWalletService extends WalletService<
final wallet = TronWallet(
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
mnemonic: mnemonic,
password: credentials.password!,
passphrase: credentials.passphrase,
@@ -55,8 +54,10 @@ class TronWalletService extends WalletService<
@override
Future<TronWallet> openWallet(String name, String password) async {
- final walletInfo =
- walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await TronWalletBase.open(
@@ -97,6 +98,7 @@ class TronWalletService extends WalletService<
password: credentials.password!,
privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -120,6 +122,7 @@ class TronWalletService extends WalletService<
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
+ derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
passphrase: credentials.passphrase,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
);
@@ -133,8 +136,10 @@ class TronWalletService extends WalletService<
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
final currentWallet = await TronWalletBase.open(
password: password,
name: currentName,
@@ -149,7 +154,7 @@ class TronWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -159,9 +164,11 @@ class TronWalletService extends WalletService<
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
- final walletInfo = walletInfoSource.values
- .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
diff --git a/cw_wownero/lib/api/wallet.dart b/cw_wownero/lib/api/wallet.dart
index a4ba8cb..68d0b65 100644
--- a/cw_wownero/lib/api/wallet.dart
+++ b/cw_wownero/lib/api/wallet.dart
@@ -102,16 +102,22 @@ String getAddress({int accountIndex = 0, int addressIndex = 1}) {
return addressCache[wptr!.address]![accountIndex]![addressIndex]!;
}
-int getFullBalance({int accountIndex = 0}) =>
- wownero.Wallet_balance(wptr!, accountIndex: accountIndex);
-
-int getUnlockedBalance({int accountIndex = 0}) =>
- wownero.Wallet_unlockedBalance(wptr!, accountIndex: accountIndex);
-
-int getCurrentHeight() => wownero.Wallet_blockChainHeight(wptr!);
+int getFullBalance({int accountIndex = 0}) {
+ if (wptr == null) return 0;
+ return wownero.Wallet_balance(wptr!, accountIndex: accountIndex);
+}
+int getUnlockedBalance({int accountIndex = 0}) {
+ if (wptr == null) return 0;
+ return wownero.Wallet_unlockedBalance(wptr!, accountIndex: accountIndex);
+}
+int getCurrentHeight() {
+ if (wptr == null) return 0;
+ return wownero.Wallet_blockChainHeight(wptr!);
+}
int cachedNodeHeight = 0;
int getNodeHeightSync() {
+ if (wptr == null) return 0;
(() async {
final wptrAddress = wptr!.address;
cachedNodeHeight = await Isolate.run(() async {
@@ -121,7 +127,10 @@ int getNodeHeightSync() {
return cachedNodeHeight;
}
-bool isConnectedSync() => wownero.Wallet_connected(wptr!) != 0;
+bool isConnectedSync() {
+ if (wptr == null) return false;
+ return wownero.Wallet_connected(wptr!) != 0;
+}
Future<bool> setupNodeSync(
{required String address,
diff --git a/cw_wownero/lib/wownero_wallet.dart b/cw_wownero/lib/wownero_wallet.dart
index f068ec4..08b7e65 100644
--- a/cw_wownero/lib/wownero_wallet.dart
+++ b/cw_wownero/lib/wownero_wallet.dart
@@ -53,7 +53,7 @@ abstract class WowneroWalletBase
extends WalletBase<WowneroBalance, WowneroTransactionHistory, WowneroTransactionInfo>
with Store {
WowneroWalletBase(
- {required WalletInfo walletInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo, required String password})
+ {required WalletInfo walletInfo, required DerivationInfo derivationInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo, required String password})
: balance = ObservableMap<CryptoCurrency, WowneroBalance>.of({
CryptoCurrency.wow: WowneroBalance(
fullBalance: wownero_wallet.getFullBalance(accountIndex: 0),
@@ -66,7 +66,7 @@ abstract class WowneroWalletBase
syncStatus = NotConnectedSyncStatus(),
unspentCoins = [],
this.unspentCoinsInfo = unspentCoinsInfo,
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
transactionHistory = WowneroTransactionHistory();
walletAddresses = WowneroWalletAddresses(walletInfo, transactionHistory);
diff --git a/cw_wownero/lib/wownero_wallet_addresses.dart b/cw_wownero/lib/wownero_wallet_addresses.dart
index 0b2ade0..936c187 100644
--- a/cw_wownero/lib/wownero_wallet_addresses.dart
+++ b/cw_wownero/lib/wownero_wallet_addresses.dart
@@ -88,8 +88,12 @@ abstract class WowneroWalletAddressesBase extends WalletAddresses with Store {
_subaddressList.subaddresses.forEach((subaddress) {
addressesMap[subaddress.address] = subaddress.label;
addressInfos[account.id] ??= [];
- addressInfos[account.id]?.add(AddressInfo(
- address: subaddress.address, label: subaddress.label, accountIndex: account.id));
+ addressInfos[account.id]?.add(WalletInfoAddressInfo(
+ walletInfoId: walletInfo.internalId,
+ mapKey: account.id,
+ accountIndex: account.id,
+ address: subaddress.address,
+ label: subaddress.label));
});
});
diff --git a/cw_wownero/lib/wownero_wallet_service.dart b/cw_wownero/lib/wownero_wallet_service.dart
index 72eefab..b8063a3 100644
--- a/cw_wownero/lib/wownero_wallet_service.dart
+++ b/cw_wownero/lib/wownero_wallet_service.dart
@@ -66,9 +66,8 @@ class WowneroWalletService extends WalletService<
WowneroRestoreWalletFromSeedCredentials,
WowneroRestoreWalletFromKeysCredentials,
WowneroNewWalletCredentials> {
- WowneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
+ WowneroWalletService(this.unspentCoinsInfoSource);
- final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
static bool walletFilesExist(String path) =>
@@ -99,7 +98,7 @@ class WowneroWalletService extends WalletService<
await wownero_wallet_manager.createWallet(
path: path, password: credentials.password!, language: credentials.language, passphrase: credentials.passphrase??'');
final wallet = WowneroWallet(
- walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
+ walletInfo: credentials.walletInfo!, derivationInfo: await credentials.walletInfo!.getDerivationInfo(), unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
await wallet.init();
return wallet;
@@ -133,9 +132,11 @@ class WowneroWalletService extends WalletService<
}
await wownero_wallet_manager.openWalletAsync({'path': path, 'password': password});
- final walletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
- wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ wallet = WowneroWallet(walletInfo: walletInfo, derivationInfo: await walletInfo.getDerivationInfo(), unspentCoinsInfo: unspentCoinsInfoSource, password: password);
final isValid = wallet.walletAddresses.validate();
if (!isValid) {
@@ -206,17 +207,20 @@ class WowneroWalletService extends WalletService<
await file.delete(recursive: true);
}
- final walletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
- final currentWallet =
- WowneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ final currentWallet = WowneroWallet(walletInfo: currentWalletInfo, derivationInfo: await currentWalletInfo.getDerivationInfo(), unspentCoinsInfo: unspentCoinsInfoSource, password: password);
await currentWallet.renameWalletFiles(newName);
@@ -224,7 +228,7 @@ class WowneroWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
@@ -241,7 +245,7 @@ class WowneroWalletService extends WalletService<
viewKey: credentials.viewKey,
spendKey: credentials.spendKey);
final wallet = WowneroWallet(
- walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
+ walletInfo: credentials.walletInfo!, derivationInfo: await credentials.walletInfo!.getDerivationInfo(), unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
await wallet.init();
return wallet;
@@ -275,7 +279,7 @@ class WowneroWalletService extends WalletService<
seed: credentials.mnemonic,
restoreHeight: credentials.height!);
final wallet = WowneroWallet(
- walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
+ walletInfo: credentials.walletInfo!, derivationInfo: await credentials.walletInfo!.getDerivationInfo(), unspentCoinsInfo: unspentCoinsInfoSource, password: credentials.password!);
await wallet.init();
return wallet;
@@ -321,6 +325,7 @@ class WowneroWalletService extends WalletService<
final wallet = WowneroWallet(
walletInfo: walletInfo,
+ derivationInfo: await walletInfo.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
);
@@ -350,7 +355,7 @@ class WowneroWalletService extends WalletService<
wownero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
wownero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase??'');
- final wallet = WowneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
+ final wallet = WowneroWallet(walletInfo: walletInfo, derivationInfo: await walletInfo.getDerivationInfo(), unspentCoinsInfo: unspentCoinsInfoSource, password: password);
await wallet.init();
return wallet;
diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock
index 8710715..2e1b3fb 100644
--- a/cw_wownero/pubspec.lock
+++ b/cw_wownero/pubspec.lock
@@ -722,6 +722,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
+ sqflite:
+ dependency: transitive
+ description:
+ name: sqflite
+ sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ sqflite_android:
+ dependency: transitive
+ description:
+ name: sqflite_android
+ sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqflite_common:
+ dependency: transitive
+ description:
+ name: sqflite_common
+ sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.4+6"
+ sqflite_common_ffi:
+ dependency: transitive
+ description:
+ name: sqflite_common_ffi
+ sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4+4"
+ sqflite_darwin:
+ dependency: transitive
+ description:
+ name: sqflite_darwin
+ sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1+1"
+ sqflite_platform_interface:
+ dependency: transitive
+ description:
+ name: sqflite_platform_interface
+ sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqlite3:
+ dependency: transitive
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
stack_trace:
dependency: transitive
description:
@@ -754,6 +810,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
diff --git a/cw_zano/lib/zano_wallet.dart b/cw_zano/lib/zano_wallet.dart
index da253e3..913bc08 100644
--- a/cw_zano/lib/zano_wallet.dart
+++ b/cw_zano/lib/zano_wallet.dart
@@ -105,14 +105,14 @@ abstract class ZanoWalletBase
/// number of transactions in each request
static final int _txChunkSize = (pow(2, 32) - 1).toInt();
- ZanoWalletBase(WalletInfo walletInfo, String password)
+ ZanoWalletBase(WalletInfo walletInfo, DerivationInfo derivationInfo, String password)
: balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance.empty()}),
_isTransactionUpdating = false,
_hasSyncAfterStartup = false,
walletAddresses = ZanoWalletAddresses(walletInfo),
syncStatus = NotConnectedSyncStatus(),
_password = password,
- super(walletInfo) {
+ super(walletInfo, derivationInfo) {
transactionHistory = ZanoTransactionHistory();
if (!CakeHive.isAdapterRegistered(ZanoAsset.typeId)) {
CakeHive.registerAdapter(ZanoAssetAdapter());
@@ -129,7 +129,7 @@ abstract class ZanoWalletBase
}
static Future<ZanoWallet> create({required WalletCredentials credentials}) async {
- final wallet = ZanoWallet(credentials.walletInfo!, credentials.password!);
+ final wallet = ZanoWallet(credentials.walletInfo!, await credentials.walletInfo!.getDerivationInfo(), credentials.password!);
await wallet.initWallet();
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
final createWalletResult = await wallet.createWallet(path, credentials.password!);
@@ -146,7 +146,7 @@ abstract class ZanoWalletBase
static Future<ZanoWallet> restore(
{required ZanoRestoreWalletFromSeedCredentials credentials}) async {
- final wallet = ZanoWallet(credentials.walletInfo!, credentials.password!);
+ final wallet = ZanoWallet(credentials.walletInfo!, await credentials.walletInfo!.getDerivationInfo(), credentials.password!);
await wallet.initWallet();
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
final createWalletResult = await wallet.restoreWalletFromSeed(
@@ -166,13 +166,13 @@ abstract class ZanoWalletBase
{required String name, required String password, required WalletInfo walletInfo}) async {
final path = await pathForWallet(name: name, type: walletInfo.type);
if (ZanoWalletApi.openWalletCache[path] != null) {
- final wallet = ZanoWallet(walletInfo, password);
+ final wallet = ZanoWallet(walletInfo, await walletInfo.getDerivationInfo(), password);
await wallet.parseCreateWalletResult(ZanoWalletApi.openWalletCache[path]!).then((_) {
unawaited(wallet.init(ZanoWalletApi.openWalletCache[path]!.wi.address));
});
return wallet;
} else {
- final wallet = ZanoWallet(walletInfo, password);
+ final wallet = ZanoWallet(walletInfo, await walletInfo.getDerivationInfo(), password);
await wallet.initWallet();
final createWalletResult = await wallet.loadWallet(path, password);
await wallet.parseCreateWalletResult(createWalletResult).then((_) {
diff --git a/cw_zano/lib/zano_wallet_service.dart b/cw_zano/lib/zano_wallet_service.dart
index 879402c..98d350a 100644
--- a/cw_zano/lib/zano_wallet_service.dart
+++ b/cw_zano/lib/zano_wallet_service.dart
@@ -43,9 +43,7 @@ class ZanoRestoreWalletFromKeysCredentials extends WalletCredentials {
class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
ZanoRestoreWalletFromSeedCredentials, ZanoRestoreWalletFromKeysCredentials, ZanoNewWalletCredentials> {
- ZanoWalletService(this.walletInfoSource);
-
- final Box<WalletInfo> walletInfoSource;
+ ZanoWalletService();
static bool walletFilesExist(String path) => !File(path).existsSync() && !File('$path.keys').existsSync();
@@ -68,7 +66,10 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
@override
Future<ZanoWallet> openWallet(String name, String password) async {
- final walletInfo = walletInfoSource.values.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
+ final walletInfo = await WalletInfo.get(name, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
try {
final wallet = await ZanoWalletBase.open(name: name, password: password, walletInfo: walletInfo);
saveBackup(name);
@@ -89,14 +90,20 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
await file.delete(recursive: true);
}
- final walletInfo = walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
- final currentWalletInfo = walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
- final currentWallet = ZanoWallet(currentWalletInfo, password);
+ final currentWalletInfo = await WalletInfo.get(currentName, getType());
+ if (currentWalletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ final currentWallet = ZanoWallet(currentWalletInfo, await currentWalletInfo.getDerivationInfo(), password);
await currentWallet.renameWalletFiles(newName);
@@ -104,7 +111,7 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
- await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
+ await newWalletInfo.save();
}
@override
diff --git a/cw_zano/pubspec.lock b/cw_zano/pubspec.lock
index 0ee7046..0c4a576 100644
--- a/cw_zano/pubspec.lock
+++ b/cw_zano/pubspec.lock
@@ -719,6 +719,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
+ sqflite:
+ dependency: transitive
+ description:
+ name: sqflite
+ sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ sqflite_android:
+ dependency: transitive
+ description:
+ name: sqflite_android
+ sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqflite_common:
+ dependency: transitive
+ description:
+ name: sqflite_common
+ sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.4+6"
+ sqflite_common_ffi:
+ dependency: transitive
+ description:
+ name: sqflite_common_ffi
+ sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4+4"
+ sqflite_darwin:
+ dependency: transitive
+ description:
+ name: sqflite_darwin
+ sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1+1"
+ sqflite_platform_interface:
+ dependency: transitive
+ description:
+ name: sqflite_platform_interface
+ sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ sqlite3:
+ dependency: transitive
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
stack_trace:
dependency: transitive
description:
@@ -751,6 +807,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
diff --git a/lib/base/cw_base.dart b/lib/base/cw_base.dart
index a3bbe53..42a9ad0 100644
--- a/lib/base/cw_base.dart
+++ b/lib/base/cw_base.dart
@@ -4,8 +4,8 @@ class CWBase extends Base {
@override
List<String> getBaseWordList(String language) => EVMChainMnemonics.englishWordlist;
- WalletService createBaseWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
- BaseWalletService(walletInfoSource, isDirect, client: BaseClient());
+ WalletService createBaseWalletService(bool isDirect) =>
+ BaseWalletService(isDirect, client: BaseClient());
@override
WalletCredentials createBaseNewWalletCredentials({
@@ -216,14 +216,15 @@ class CWBase extends Base {
@override
- void setHardwareWalletService(WalletBase wallet, HardwareWalletService service) {
+ Future<void> setHardwareWalletService(WalletBase wallet, HardwareWalletService service) async {
if (service is EVMChainLedgerService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials).setLedgerConnection(
- service.ledgerConnection, wallet.walletInfo.derivationInfo?.derivationPath);
+ service.ledgerConnection, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
} else if (service is EVMChainBitboxService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmBitboxCredentials)
- .setBitbox(service.manager, wallet.walletInfo.derivationInfo?.derivationPath);
+ .setBitbox(service.manager, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
}
+ return Future.value();
}
@override
diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart
index 452b802..4a9b2f1 100644
--- a/lib/bitcoin/cw_bitcoin.dart
+++ b/lib/bitcoin/cw_bitcoin.dart
@@ -260,17 +260,14 @@ class CWBitcoin extends Bitcoin {
}
WalletService createBitcoinWalletService(
- Box<WalletInfo> walletInfoSource,
Box<UnspentCoinsInfo> unspentCoinSource,
Box<PayjoinSession> payjoinSessionSource,
bool isDirect) {
- return BitcoinWalletService(
- walletInfoSource, unspentCoinSource, payjoinSessionSource, isDirect);
+ return BitcoinWalletService(unspentCoinSource, payjoinSessionSource, isDirect);
}
- WalletService createLitecoinWalletService(
- Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
- return LitecoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
+ WalletService createLitecoinWalletService(Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
+ return LitecoinWalletService(unspentCoinSource, isDirect);
}
@override
@@ -537,7 +534,7 @@ class CWBitcoin extends Bitcoin {
}
@override
- void setHardwareWalletService(WalletBase wallet, HardwareWalletService service) {
+ Future<void> setHardwareWalletService(WalletBase wallet, HardwareWalletService service) async {
(wallet as ElectrumWallet).hardwareWalletService = service;
}
diff --git a/lib/bitcoin_cash/cw_bitcoin_cash.dart b/lib/bitcoin_cash/cw_bitcoin_cash.dart
index be0323b..5039652 100644
--- a/lib/bitcoin_cash/cw_bitcoin_cash.dart
+++ b/lib/bitcoin_cash/cw_bitcoin_cash.dart
@@ -5,9 +5,8 @@ class CWBitcoinCash extends BitcoinCash {
String getCashAddrFormat(String address) => AddressUtils.getCashAddrFormat(address);
@override
- WalletService createBitcoinCashWalletService(
- Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
- return BitcoinCashWalletService(walletInfoSource, unspentCoinSource, isDirect);
+ WalletService createBitcoinCashWalletService(Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
+ return BitcoinCashWalletService(unspentCoinSource, isDirect);
}
@override
diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart
index 87bb71c..6a0f668 100644
--- a/lib/core/backup_service.dart
+++ b/lib/core/backup_service.dart
@@ -24,7 +24,7 @@ import 'package:cake_wallet/wallet_types.g.dart';
import 'package:cake_backup/backup.dart' as cake_backup;
class $BackupService {
- $BackupService(this._secureStorage, this.walletInfoSource, this.transactionDescriptionBox,
+ $BackupService(this._secureStorage, this.transactionDescriptionBox,
this.keyService, this.sharedPreferences)
: cipher = Cryptography.instance.chacha20Poly1305Aead(),
correctWallets = <WalletInfo>[];
@@ -37,7 +37,6 @@ class $BackupService {
final Cipher cipher;
final SecureStorage _secureStorage;
final SharedPreferences sharedPreferences;
- final Box<WalletInfo> walletInfoSource;
final Box<TransactionDescription> transactionDescriptionBox;
final KeyService keyService;
List<WalletInfo> correctWallets;
@@ -110,27 +109,14 @@ class $BackupService {
}
Future<void> verifyWallets() async {
- final walletInfoSource = await reloadHiveWalletInfoBox();
- correctWallets =
- walletInfoSource.values.where((info) => availableWalletTypes.contains(info.type)).toList();
+ await performHiveMigration(); // for backups made before sqlite migration
+ correctWallets = (await WalletInfo.getAll()).where((info) => availableWalletTypes.contains(info.type)).toList();
if (correctWallets.isEmpty) {
- throw Exception('Correct wallets not detected');
+ printV('Correct wallets not detected');
}
}
- Future<Box<WalletInfo>> reloadHiveWalletInfoBox() async {
- final appDir = await getAppDir();
- await CakeHive.close();
- CakeHive.init(appDir.path);
-
- if (!CakeHive.isAdapterRegistered(WalletInfo.typeId)) {
- CakeHive.registerAdapter(WalletInfoAdapter());
- }
-
- return await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
- }
-
Future<void> importTransactionDescriptionDump() async {
final appDir = await getAppDir();
final transactionDescriptionFile = File('${appDir.path}/~_transaction_descriptions_dump');
@@ -191,12 +177,16 @@ class $BackupService {
String currentWalletName = data[PreferencesKey.currentWalletName] as String;
int currentWalletType = data[PreferencesKey.currentWalletType] as int;
- final isCorrentCurrentWallet = correctWallets
+ final isCorrectCurrentWallet = correctWallets
.any((info) => info.name == currentWalletName && info.type.index == currentWalletType);
- if (!isCorrentCurrentWallet) {
- currentWalletName = correctWallets.first.name;
- currentWalletType = serializeToInt(correctWallets.first.type);
+ try {
+ if (!isCorrectCurrentWallet) {
+ currentWalletName = correctWallets.first.name;
+ currentWalletType = serializeToInt(correctWallets.first.type);
+ }
+ } catch (e) {
+
}
if (DeviceInfo.instance.isDesktop) {
@@ -283,7 +273,7 @@ class $BackupService {
Future<Uint8List> exportKeychainDumpV2(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
- final wallets = await Future.wait(walletInfoSource.values.map((walletInfo) async {
+ final wallets = await Future.wait((await WalletInfo.getAll()).map((walletInfo) async {
try {
return {
'name': walletInfo.name,
diff --git a/lib/core/backup_service_v3.dart b/lib/core/backup_service_v3.dart
index a0640df..ac73f9b 100644
--- a/lib/core/backup_service_v3.dart
+++ b/lib/core/backup_service_v3.dart
@@ -11,6 +11,7 @@ import 'package:crypto/crypto.dart';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart';
+import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
enum BackupVersion {
@@ -143,7 +144,7 @@ class BackupMetadata {
}
class BackupServiceV3 extends $BackupService {
- BackupServiceV3(super.secureStorage, super.walletInfoSource, super.transactionDescriptionBox, super.keyService, super.sharedPreferences);
+ BackupServiceV3(super.secureStorage, super.transactionDescriptionBox, super.keyService, super.sharedPreferences);
static BackupVersion get currentVersion => BackupVersion.v3;
@@ -317,7 +318,6 @@ class BackupServiceV3 extends $BackupService {
Future<void> verifyHardwareWallets(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
- final walletInfoSource = await reloadHiveWalletInfoBox();
final appDir = await getAppDir();
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
final decryptedKeychainDumpFileData = await decryptV2(
@@ -334,10 +334,7 @@ class BackupServiceV3 extends $BackupService {
for (final expectedHardwareWallet in expectedHardwareWallets) {
final info = expectedHardwareWallet as Map<String, dynamic>;
- final actualWalletInfo = walletInfoSource.values
- .where((e) =>
- e.name == info['name'] && e.type.toString() == info['type'])
- .firstOrNull;
+ final actualWalletInfo = await WalletInfo.get(info['name'] as String, WalletType.values.firstWhere((e) => e.toString() == info['type'] as String));
if (actualWalletInfo != null &&
info["hardwareWalletType"] !=
actualWalletInfo.hardwareWalletType?.index) {
diff --git a/lib/core/wallet_creation_service.dart b/lib/core/wallet_creation_service.dart
index 254f8a1..dec1c80 100644
--- a/lib/core/wallet_creation_service.dart
+++ b/lib/core/wallet_creation_service.dart
@@ -16,8 +16,7 @@ class WalletCreationService {
{required WalletType initialType,
required this.keyService,
required this.sharedPreferences,
- required this.settingsStore,
- required this.walletInfoSource})
+ required this.settingsStore})
: type = initialType {
changeWalletType(type: type);
}
@@ -26,7 +25,6 @@ class WalletCreationService {
final SharedPreferences sharedPreferences;
final SettingsStore settingsStore;
final KeyService keyService;
- final Box<WalletInfo> walletInfoSource;
WalletService? _service;
static const _isNewMoneroWalletPasswordUpdated = true;
@@ -36,23 +34,23 @@ class WalletCreationService {
_service = getIt.get<WalletService>(param1: type);
}
- bool exists(String name) {
+ Future<bool> exists(String name) async {
final walletName = name.toLowerCase();
- return walletInfoSource.values.any((walletInfo) => walletInfo.name.toLowerCase() == walletName);
+ return (await WalletInfo.getAll()).any((walletInfo) => walletInfo.name.toLowerCase() == walletName);
}
- bool typeExists(WalletType type) {
- return walletInfoSource.values.any((walletInfo) => walletInfo.type == type);
+ Future<bool> typeExists(WalletType type) async {
+ return (await WalletInfo.getAll()).any((walletInfo) => walletInfo.type == type);
}
- void checkIfExists(String name) {
- if (exists(name)) {
+ Future<void> checkIfExists(String name) async {
+ if (await exists(name)) {
throw Exception('Wallet with name ${name} already exists!');
}
}
Future<WalletBase> create(WalletCredentials credentials, {bool? isTestnet}) async {
- checkIfExists(credentials.name);
+ await checkIfExists(credentials.name);
if (credentials.password == null) {
credentials.password = generateWalletPassword();
@@ -84,12 +82,12 @@ class WalletCreationService {
case WalletType.solana:
case WalletType.tron:
case WalletType.dogecoin:
+ case WalletType.nano:
return true;
case WalletType.monero:
case WalletType.wownero:
case WalletType.none:
case WalletType.haven:
- case WalletType.nano:
case WalletType.banano:
case WalletType.zano:
case WalletType.decred:
diff --git a/lib/core/wallet_loading_service.dart b/lib/core/wallet_loading_service.dart
index 1432ce6..f6fb767 100644
--- a/lib/core/wallet_loading_service.dart
+++ b/lib/core/wallet_loading_service.dart
@@ -74,7 +74,7 @@ class WalletLoadingService {
} catch (error, stack) {
await ExceptionHandler.resetLastPopupDate();
final isLedgerError = await ExceptionHandler.isLedgerError(error);
- if (isLedgerError || requireHardwareWalletConnection(type, name)) rethrow;
+ if (isLedgerError || await requireHardwareWalletConnection(type, name)) rethrow;
await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
@@ -87,9 +87,8 @@ class WalletLoadingService {
}
// try opening another wallet that is not corrupted to give user access to the app
- final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
WalletBase? wallet;
- for (var walletInfo in walletInfoSource.values) {
+ for (var walletInfo in await WalletInfo.getAll()) {
try {
final walletService = walletServiceFactory.call(walletInfo.type);
final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name);
@@ -195,8 +194,8 @@ class WalletLoadingService {
return "\n\n$type ($name): ${await walletService.getSeeds(name, password, type)}";
}
- bool requireHardwareWalletConnection(WalletType type, String name) {
+ Future<bool> requireHardwareWalletConnection(WalletType type, String name) async {
final walletService = walletServiceFactory.call(type);
- return walletService.requireHardwareWalletConnection(name);
+ return await walletService.requireHardwareWalletConnection(name);
}
}
diff --git a/lib/decred/cw_decred.dart b/lib/decred/cw_decred.dart
index 2838959..7fe2ee5 100644
--- a/lib/decred/cw_decred.dart
+++ b/lib/decred/cw_decred.dart
@@ -19,9 +19,8 @@ class CWDecred extends Decred {
DecredRestoreWalletFromPubkeyCredentials(name: name, pubkey: pubkey, password: password);
@override
- WalletService createDecredWalletService(
- Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
- return DecredWalletService(walletInfoSource, unspentCoinSource);
+ WalletService createDecredWalletService(Box<UnspentCoinsInfo> unspentCoinSource) {
+ return DecredWalletService(unspentCoinSource);
}
@override
@@ -53,7 +52,7 @@ class CWDecred extends Decred {
.toList(),
priority: priority as DecredTransactionPriority);
- List<AddressInfo> getAddressInfos(Object wallet) {
+ List<WalletInfoAddressInfo> getAddressInfos(Object wallet) {
final decredWallet = wallet as DecredWallet;
return decredWallet.walletAddresses.getAddressInfos();
}
diff --git a/lib/di.dart b/lib/di.dart
index 8f0a712..1d4a0ac 100644
--- a/lib/di.dart
+++ b/lib/di.dart
@@ -2,7 +2,6 @@ import 'dart:async' show Timer;
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/anonpay/anonpay_api.dart';
-import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
import 'package:cake_wallet/anypay/anypay_api.dart';
import 'package:cake_wallet/base/base.dart';
@@ -301,7 +300,6 @@ import 'package:cake_wallet/view_model/wallet_switcher_view_model.dart';
final getIt = GetIt.instance;
var _isSetupFinished = false;
-late Box<WalletInfo> _walletInfoSource;
late Box<Node> _nodeSource;
late Box<Node> _powNodeSource;
late Box<Contact> _contactSource;
@@ -315,7 +313,6 @@ late Box<PayjoinSession> _payjoinSessionSource;
late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
Future<void> setup({
- required Box<WalletInfo> walletInfoSource,
required Box<Node> nodeSource,
required Box<Node> powNodeSource,
required Box<Contact> contactSource,
@@ -330,7 +327,6 @@ Future<void> setup({
required SecureStorage secureStorage,
required GlobalKey<NavigatorState> navigatorKey,
}) async {
- _walletInfoSource = walletInfoSource;
_nodeSource = nodeSource;
_powNodeSource = powNodeSource;
_contactSource = contactSource;
@@ -432,7 +428,7 @@ Future<void> setup({
keyService: getIt.get<KeyService>(),
sharedPreferences: getIt.get<SharedPreferences>(),
settingsStore: getIt.get<SettingsStore>(),
- walletInfoSource: _walletInfoSource));
+ ));
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>(
(type, _) => AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
@@ -446,17 +442,17 @@ Future<void> setup({
(newWalletArgs, _) => WalletNewVM(
getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1:newWalletArgs.type),
- _walletInfoSource,
getIt.get<AdvancedPrivacySettingsViewModel>(param1: newWalletArgs.type),
getIt.get<SeedSettingsViewModel>(),
- newWalletArguments: newWalletArgs,));
+ newWalletArguments: newWalletArgs,
+ ));
- getIt.registerFactory<NewWalletTypeViewModel>(() => NewWalletTypeViewModel(_walletInfoSource));
+ final walletList = await WalletInfo.getAll();
+ getIt.registerFactory<NewWalletTypeViewModel>(() => NewWalletTypeViewModel(walletList.isNotEmpty));
getIt.registerFactory<WalletManager>(
() => WalletManager(
- _walletInfoSource,
getIt.get<SharedPreferences>(),
),
);
@@ -535,7 +531,6 @@ Future<void> setup({
hardwareWalletVM,
getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
- _walletInfoSource,
getIt.get<SeedSettingsViewModel>(),
type: type));
@@ -560,7 +555,6 @@ Future<void> setup({
getIt.get<ContactListViewModel>(),
getIt.get<UnspentCoinsListViewModel>(),
getIt.get<FeesViewModel>(),
- _walletInfoSource,
getIt.get<FiatConversionStore>(),
),
);
@@ -639,7 +633,7 @@ Future<void> setup({
getIt.registerFactory<AuthPage>(instanceName: 'login', () {
return AuthPage(getIt.get<AuthViewModel>(), closable: false,
- onAuthenticationFinished: (isAuthenticated, AuthPageState authPageState) {
+ onAuthenticationFinished: (isAuthenticated, AuthPageState authPageState) async {
if (!isAuthenticated) {
return;
}
@@ -680,7 +674,7 @@ Future<void> setup({
);
} else {
// wallet is already loaded:
- if (appStore.wallet != null || requireHardwareWalletConnection()) {
+ if (appStore.wallet != null || await requireHardwareWalletConnection()) {
// goes to the dashboard:
authStore.allowed();
// trigger any deep links:
@@ -847,8 +841,7 @@ Future<void> setup({
: null,
coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.nonMweb,
getIt.get<UnspentCoinsListViewModel>(param1: coinTypeToSpendFrom),
- getIt.get<FeesViewModel>(),
- _walletInfoSource,
+ getIt.get<FeesViewModel>()
),
);
@@ -867,7 +860,6 @@ Future<void> setup({
if (DeviceInfo.instance.isMobile) {
getIt.registerFactory(
() => WalletListViewModel(
- _walletInfoSource,
getIt.get<AppStore>(),
getIt.get<WalletLoadingService>(),
getIt.get<WalletManager>(),
@@ -878,7 +870,6 @@ Future<void> setup({
// from multiple places at the same time (Wallets DropDown, Wallets List in settings)
getIt.registerLazySingleton(
() => WalletListViewModel(
- _walletInfoSource,
getIt.get<AppStore>(),
getIt.get<WalletLoadingService>(),
getIt.get<WalletManager>(),
@@ -890,7 +881,7 @@ Future<void> setup({
(Function(BuildContext)? onWalletLoaded, _) => WalletListPage(
walletListViewModel: getIt.get<WalletListViewModel>(),
authService: getIt.get<AuthService>(),
- onWalletLoaded: onWalletLoaded,
+ onWalletLoaded: onWalletLoaded as Future<void> Function(BuildContext)?,
));
getIt.registerFactoryParam<WalletEditViewModel, WalletListViewModel, void>(
@@ -1034,7 +1025,7 @@ Future<void> setup({
getIt.registerFactoryParam<ContactListViewModel, CryptoCurrency?, void>(
(CryptoCurrency? cur, _) =>
- ContactListViewModel(_contactSource, _walletInfoSource, cur, getIt.get<SettingsStore>()));
+ ContactListViewModel(_contactSource, walletList, cur, getIt.get<SettingsStore>()));
getIt.registerFactoryParam<ContactListPage, CryptoCurrency?, void>((CryptoCurrency? cur, _) =>
ContactListPage(getIt.get<ContactListViewModel>(param1: cur), getIt.get<AuthService>()));
@@ -1190,62 +1181,53 @@ Future<void> setup({
getIt.registerFactory(() => PaymentViewModel(
appStore: getIt.get<AppStore>(),
- walletInfoSource: _walletInfoSource,
));
getIt.registerFactory(() => WalletSwitcherViewModel(
appStore: getIt.get<AppStore>(),
walletLoadingService: getIt.get<WalletLoadingService>(),
- walletInfoSource: _walletInfoSource,
));
getIt.registerFactoryParam<WalletService, WalletType, void>((WalletType param1, __) {
switch (param1) {
case WalletType.monero:
- return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
+ return monero!.createMoneroWalletService(_unspentCoinsInfoSource);
case WalletType.bitcoin:
return bitcoin!.createBitcoinWalletService(
- _walletInfoSource,
_unspentCoinsInfoSource,
_payjoinSessionSource,
SettingsStoreBase.walletPasswordDirectInput,
);
case WalletType.litecoin:
return bitcoin!.createLitecoinWalletService(
- _walletInfoSource,
_unspentCoinsInfoSource,
SettingsStoreBase.walletPasswordDirectInput,
);
case WalletType.ethereum:
- return ethereum!.createEthereumWalletService(
- _walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return ethereum!.createEthereumWalletService(SettingsStoreBase.walletPasswordDirectInput);
case WalletType.bitcoinCash:
- return bitcoinCash!.createBitcoinCashWalletService(_walletInfoSource,
- _unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return bitcoinCash!.createBitcoinCashWalletService(_unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput);
case WalletType.dogecoin:
- return dogecoin!.createDogeCoinWalletService(_walletInfoSource,
- _unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return dogecoin!.createDogeCoinWalletService(_unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput);
case WalletType.nano:
case WalletType.banano:
- return nano!.createNanoWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return nano!.createNanoWalletService(SettingsStoreBase.walletPasswordDirectInput);
case WalletType.polygon:
- return polygon!.createPolygonWalletService(
- _walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return polygon!.createPolygonWalletService(SettingsStoreBase.walletPasswordDirectInput);
case WalletType.solana:
- return solana!.createSolanaWalletService(
- _walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return solana!.createSolanaWalletService(SettingsStoreBase.walletPasswordDirectInput);
case WalletType.tron:
- return tron!.createTronWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return tron!.createTronWalletService(SettingsStoreBase.walletPasswordDirectInput);
case WalletType.wownero:
- return wownero!.createWowneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
+ return wownero!.createWowneroWalletService(_unspentCoinsInfoSource);
case WalletType.zano:
- return zano!.createZanoWalletService(_walletInfoSource);
+ return zano!.createZanoWalletService();
case WalletType.decred:
- return decred!.createDecredWalletService(_walletInfoSource, _unspentCoinsInfoSource);
+ return decred!.createDecredWalletService(_unspentCoinsInfoSource);
case WalletType.base:
- return base!.createBaseWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
+ return base!.createBaseWalletService(SettingsStoreBase.walletPasswordDirectInput);
case WalletType.haven:
- return HavenWalletService(_walletInfoSource);
+ return HavenWalletService();
case WalletType.none:
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
}
@@ -1275,7 +1257,6 @@ Future<void> setup({
return WalletRestoreViewModel(
getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
- _walletInfoSource,
getIt.get<SeedSettingsViewModel>(),
type: type,
restoredWallet: restoredWallet,
@@ -1351,7 +1332,7 @@ Future<void> setup({
getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get<CakePayService>()));
- getIt.registerFactory(() => BackupServiceV3(getIt.get<SecureStorage>(), _walletInfoSource,
+ getIt.registerFactory(() => BackupServiceV3(getIt.get<SecureStorage>(),
_transactionDescriptionBox,
getIt.get<KeyService>(), getIt.get<SharedPreferences>()));
diff --git a/lib/dogecoin/cw_dogecoin.dart b/lib/dogecoin/cw_dogecoin.dart
index e781193..90aaa7b 100644
--- a/lib/dogecoin/cw_dogecoin.dart
+++ b/lib/dogecoin/cw_dogecoin.dart
@@ -4,9 +4,8 @@ part of 'dogecoin.dart';
class CWDogeCoin extends DogeCoin {
@override
- WalletService createDogeCoinWalletService(
- Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
- return DogeCoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
+ WalletService createDogeCoinWalletService(Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
+ return DogeCoinWalletService(unspentCoinSource, isDirect);
}
@override
diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart
index c25891e..8367147 100644
--- a/lib/entities/default_settings_migration.dart
+++ b/lib/entities/default_settings_migration.dart
@@ -5,6 +5,7 @@ import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/haven_seed_store.dart';
+import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cw_core/root_dir.dart';
@@ -21,6 +22,7 @@ import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/entities/contact.dart';
import 'package:cake_wallet/entities/fs_migration.dart';
import 'package:cw_core/wallet_info.dart';
+import 'package:cw_core/wallet_info_legacy.dart' as wiLegacy;
import 'package:cake_wallet/exchange/trade.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:collection/collection.dart';
@@ -55,12 +57,11 @@ Future<void> defaultSettingsMigration(
required SecureStorage secureStorage,
required Box<Node> nodes,
required Box<Node> powNodes,
- required Box<WalletInfo> walletInfoSource,
required Box<Trade> tradeSource,
required Box<Contact> contactSource,
required Box<HavenSeedStore> havenSeedStore}) async {
if (Platform.isIOS) {
- await ios_migrate_v1(walletInfoSource, tradeSource, contactSource);
+ await ios_migrate_v1(tradeSource, contactSource);
}
// check current nodes for nullability regardless of the version
@@ -69,7 +70,7 @@ Future<void> defaultSettingsMigration(
final isNewInstall =
sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null;
- await _validateWalletInfoBoxData(walletInfoSource);
+ await _validateWalletInfoBoxData();
await sharedPreferences.setBool(PreferencesKey.isNewInstall, isNewInstall);
@@ -162,7 +163,7 @@ Future<void> defaultSettingsMigration(
break;
case 5:
- await addAddressesForMoneroWallets(walletInfoSource);
+ await addAddressesForMoneroWallets();
break;
case 6:
@@ -323,7 +324,7 @@ Future<void> defaultSettingsMigration(
await updateNanoNodeList(nodes: nodes);
break;
case 32:
- await updateBtcNanoWalletInfos(walletInfoSource);
+ await updateBtcNanoWalletInfos();
break;
case 33:
await addWalletNodeList(nodes: nodes, type: WalletType.tron);
@@ -361,7 +362,7 @@ Future<void> defaultSettingsMigration(
// await replaceTronDefaultNode(sharedPreferences: sharedPreferences, nodes: nodes);
break;
case 38:
- await fixBtcDerivationPaths(walletInfoSource);
+ await fixBtcDerivationPaths();
break;
case 39:
_fixNodesUseSSLFlag(nodes);
@@ -738,7 +739,7 @@ Future<void> _updateMoneroPriority(SharedPreferences sharedPreferences) async {
}
}
-Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async {
+Future<void> _validateWalletInfoBoxData() async {
try {
final root = await getAppDir();
@@ -780,7 +781,7 @@ Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async
}
final id = prefix + '_' + name;
- final exist = walletInfoSource.values.any((el) => el.id == id);
+ final exist = (await WalletInfo.getAll()).any((el) => el.id == id);
if (exist) {
continue;
@@ -799,7 +800,7 @@ Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async
showIntroCakePayCard: false,
);
- walletInfoSource.add(walletInfo);
+ await walletInfo.save();
}
}
} catch (_) {}
@@ -967,8 +968,8 @@ Future<void> updateNodeTypes({required Box<Node> nodes}) async {
});
}
-Future<void> addAddressesForMoneroWallets(Box<WalletInfo> walletInfoSource) async {
- final moneroWalletsInfo = walletInfoSource.values.where((info) => info.type == WalletType.monero);
+Future<void> addAddressesForMoneroWallets() async {
+ final moneroWalletsInfo = (await WalletInfo.getAll()).where((info) => info.type == WalletType.monero);
moneroWalletsInfo.forEach((info) async {
try {
final walletPath = await pathForWallet(name: info.name, type: WalletType.monero);
@@ -1016,32 +1017,34 @@ Future<void> changeTransactionPriorityAndFeeRateKeys(SharedPreferences sharedPre
bitcoin!.getMediumTransactionPriority().serialize());
}
-Future<void> fixBtcDerivationPaths(Box<WalletInfo> walletsInfoSource) async {
- for (WalletInfo walletInfo in walletsInfoSource.values) {
+Future<void> fixBtcDerivationPaths() async {
+ for (WalletInfo walletInfo in await WalletInfo.getAll()) {
if (walletInfo.type == WalletType.bitcoin ||
walletInfo.type == WalletType.bitcoinCash ||
walletInfo.type == WalletType.litecoin) {
- if (walletInfo.derivationInfo?.derivationPath == "m/0'/0") {
- walletInfo.derivationInfo!.derivationPath = "m/0'";
+ final derivationInfo = await walletInfo.getDerivationInfo();
+ if (derivationInfo?.derivationPath == "m/0'/0") {
+ derivationInfo!.derivationPath = "m/0'";
await walletInfo.save();
}
}
}
}
-
-Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
- for (WalletInfo walletInfo in walletsInfoSource.values) {
- if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) {
- walletInfo.derivationInfo = DerivationInfo(
- derivationPath: walletInfo.derivationPath,
- derivationType: walletInfo.derivationType,
- address: walletInfo.address,
- transactionsCount: walletInfo.restoreHeight,
- );
- await walletInfo.save();
- }
- }
-}
+Future<void> updateBtcNanoWalletInfos() async {}
+// Future<void> updateBtcNanoWalletInfos() async {
+// for (WalletInfo walletInfo in await WalletInfo.getAll()) {
+// if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) {
+// final derivationInfo = await walletInfo.getDerivationInfo();
+// derivationInfo = DerivationInfo(
+// derivationPath: derivationInfo?.derivationPath,
+// derivationType: derivationInfo?.derivationType,
+// address: walletInfo.address,
+// transactionsCount: walletInfo.restoreHeight,
+// );
+// await walletInfo.save();
+// }
+// }
+// }
Future<void> checkCurrentNodes(
Box<Node> nodeSource, Box<Node> powNodeSource, SharedPreferences sharedPreferences) async {
diff --git a/lib/entities/fs_migration.dart b/lib/entities/fs_migration.dart
index a7604f4..a85c579 100644
--- a/lib/entities/fs_migration.dart
+++ b/lib/entities/fs_migration.dart
@@ -29,8 +29,7 @@ Future<void> migrate_android_v1() async {
await android_migrate_wallets(appDocDir: appDocDir);
}
-Future<void> ios_migrate_v1(
- Box<WalletInfo> walletInfoSource, Box<Trade> tradeSource, Box<Contact> contactSource) async {
+Future<void> ios_migrate_v1(Box<Trade> tradeSource, Box<Contact> contactSource) async {
final prefs = await SharedPreferences.getInstance();
if (prefs.getBool('ios_migration_v1_completed') ?? false) {
@@ -40,7 +39,7 @@ Future<void> ios_migrate_v1(
await ios_migrate_user_defaults();
await ios_migrate_pin();
await ios_migrate_wallet_passwords();
- await ios_migrate_wallet_info(walletInfoSource);
+ await ios_migrate_wallet_info();
await ios_migrate_trades_list(tradeSource);
await ios_migrate_address_book(contactSource);
@@ -278,7 +277,7 @@ Future<void> android_migrate_wallets({required Directory appDocDir}) async {
});
}
-Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
+Future<void> ios_migrate_wallet_info() async {
final prefs = await SharedPreferences.getInstance();
if (prefs.getBool('ios_migration_wallet_info_completed') ?? false) {
@@ -289,6 +288,7 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
final appDocDir = await getApplicationDocumentsDirectory();
final walletsDir = Directory('${appDocDir.path}/wallets');
final moneroWalletsDir = Directory('${walletsDir.path}/monero');
+ final walletsInfo = await WalletInfo.getAll();
final infoRecords = moneroWalletsDir
.listSync()
.map((item) {
@@ -307,7 +307,7 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
final timestamp = dateAsDouble.toInt() * 1000;
final date = DateTime.fromMillisecondsSinceEpoch(timestamp);
final id = walletTypeToString(WalletType.monero).toLowerCase() + '_' + name;
- final exist = walletsInfoSource.values.firstWhereOrNull((el) => el.id == id) != null;
+ final exist = walletsInfo.firstWhereOrNull((el) => el.id == id) != null;
if (exist) {
return null;
@@ -334,7 +334,9 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
.where((el) => el != null)
.whereType<WalletInfo>()
.toList();
- await walletsInfoSource.addAll(infoRecords);
+ for (final info in infoRecords) {
+ await info.save();
+ }
await prefs.setBool('ios_migration_wallet_info_completed', true);
} catch (e) {
printV(e.toString());
diff --git a/lib/entities/hardware_wallet/require_hardware_wallet_connection.dart b/lib/entities/hardware_wallet/require_hardware_wallet_connection.dart
index a64fa58..3da6dcb 100644
--- a/lib/entities/hardware_wallet/require_hardware_wallet_connection.dart
+++ b/lib/entities/hardware_wallet/require_hardware_wallet_connection.dart
@@ -4,7 +4,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:shared_preferences/shared_preferences.dart';
-bool requireHardwareWalletConnection() {
+Future<bool> requireHardwareWalletConnection() async {
final name = getIt
.get<SharedPreferences>()
.getString(PreferencesKey.currentWalletName);
@@ -21,5 +21,5 @@ bool requireHardwareWalletConnection() {
final type = deserializeFromInt(typeRaw);
final walletLoadingService = getIt.get<WalletLoadingService>();
- return walletLoadingService.requireHardwareWalletConnection(type, name);
+ return await walletLoadingService.requireHardwareWalletConnection(type, name);
}
diff --git a/lib/entities/wallet_manager.dart b/lib/entities/wallet_manager.dart
index 09b7642..dd88c93 100644
--- a/lib/entities/wallet_manager.dart
+++ b/lib/entities/wallet_manager.dart
@@ -8,17 +8,16 @@ import 'package:hive/hive.dart';
import 'package:shared_preferences/shared_preferences.dart';
class WalletManager {
- WalletManager(this._walletInfoSource, this._sharedPreferences);
+ WalletManager(this._sharedPreferences);
- final Box<WalletInfo> _walletInfoSource;
final SharedPreferences _sharedPreferences;
final List<WalletGroup> walletGroups = [];
- void updateWalletGroups() {
+ Future<void> updateWalletGroups() async {
walletGroups.clear();
- for (final walletInfo in _walletInfoSource.values) {
+ for (final walletInfo in await WalletInfo.getAll()) {
final groupKey = _resolveGroupKey(walletInfo);
final group = _getOrCreateGroup(groupKey);
group.wallets.add(walletInfo);
@@ -115,7 +114,7 @@ class WalletManager {
// If the openedWallet already has an hash, then there is nothing to do
if (walletInfo.hashedWalletIdentifier != null &&
walletInfo.hashedWalletIdentifier!.isNotEmpty) {
- updateWalletGroups(); // Still skeptical of calling this here. Looking for a better spot.
+ await updateWalletGroups(); // Still skeptical of calling this here. Looking for a better spot.
return;
}
@@ -123,7 +122,7 @@ class WalletManager {
final oldGroupKey = _resolveGroupKey(walletInfo); // parentAddress fallback
// Find all wallets that share this old group key (i.e the old group)
- final oldGroupWallets = _walletInfoSource.values.where((w) {
+ final oldGroupWallets = (await WalletInfo.getAll()).where((w) {
final key = w.hashedWalletIdentifier != null && w.hashedWalletIdentifier!.isNotEmpty
? w.hashedWalletIdentifier
: (w.parentAddress ?? w.address);
@@ -150,7 +149,7 @@ class WalletManager {
}
// Finally, we rebuild the groups so that these wallets are now in the new group
- updateWalletGroups();
+ await updateWalletGroups();
}
/// Copy an old group name to the new group key, then remove the old key.
diff --git a/lib/ethereum/cw_ethereum.dart b/lib/ethereum/cw_ethereum.dart
index 92d8bbe..4433a54 100644
--- a/lib/ethereum/cw_ethereum.dart
+++ b/lib/ethereum/cw_ethereum.dart
@@ -4,8 +4,8 @@ class CWEthereum extends Ethereum {
@override
List<String> getEthereumWordList(String language) => EVMChainMnemonics.englishWordlist;
- WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
- EthereumWalletService(walletInfoSource, isDirect, client: EthereumClient());
+ WalletService createEthereumWalletService(bool isDirect) =>
+ EthereumWalletService(isDirect, client: EthereumClient());
@override
WalletCredentials createEthereumNewWalletCredentials({
@@ -181,18 +181,19 @@ class CWEthereum extends Ethereum {
String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress;
@override
- void setHardwareWalletService(WalletBase wallet, HardwareWalletService service) {
+ Future<void> setHardwareWalletService(WalletBase wallet, HardwareWalletService service) async {
if (service is EVMChainLedgerService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials).setLedgerConnection(
- service.ledgerConnection, wallet.walletInfo.derivationInfo?.derivationPath);
+ service.ledgerConnection, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
} else if (service is EVMChainBitboxService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmBitboxCredentials)
- .setBitbox(service.manager, wallet.walletInfo.derivationInfo?.derivationPath);
+ .setBitbox(service.manager, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
} else if (service is EVMChainTrezorService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmTrezorCredentials)
- .setTrezorConnect(service.connect, wallet.walletInfo.derivationInfo?.derivationPath);
+ .setTrezorConnect(service.connect, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
}
}
+
@override
HardwareWalletService getLedgerHardwareWalletService(ledger.LedgerConnection connection) =>
EVMChainLedgerService(connection);
diff --git a/lib/haven/cw_haven.dart b/lib/haven/cw_haven.dart
index b69e733..53cadb9 100644
--- a/lib/haven/cw_haven.dart
+++ b/lib/haven/cw_haven.dart
@@ -12,16 +12,15 @@ import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
class HavenWalletService extends WalletService {
- final Box<WalletInfo> walletInfoSource;
- HavenWalletService(this.walletInfoSource);
+ HavenWalletService();
@override
WalletType getType() => WalletType.haven;
@override
Future<void> remove(String wallet) async {
- final path = await pathForWalletDir(name: wallet, type: WalletType.haven);
+ final path = await pathForWalletDir(name: wallet, type: getType());
final file = Directory(path);
final isExist = file.existsSync();
@@ -30,9 +29,11 @@ class HavenWalletService extends WalletService {
await file.delete(recursive: true);
}
- final walletInfo = walletInfoSource.values
- .firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
- await walletInfoSource.delete(walletInfo.key);
+ final walletInfo = await WalletInfo.get(wallet, getType());
+ if (walletInfo == null) {
+ throw Exception('Wallet not found');
+ }
+ await WalletInfo.delete(walletInfo);
}
@override
diff --git a/lib/locales/yoruba_intl.dart b/lib/locales/yoruba_intl.dart
index 66afd8f..684c942 100644
--- a/lib/locales/yoruba_intl.dart
+++ b/lib/locales/yoruba_intl.dart
@@ -1032,7 +1032,7 @@ class YoCupertinoLocalizations extends GlobalCupertinoLocalizations {
@override
// TODO: implement backButtonLabel
String get backButtonLabel => "backButtonLabel";
-
+
@override
// TODO: implement cancelButtonLabel
String get cancelButtonLabel => "cancelButtonLabel";
diff --git a/lib/main.dart b/lib/main.dart
index beaa152..a5b9be8 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -47,8 +47,9 @@ import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
-import 'package:cw_core/utils/tor/abstract.dart';
+import 'package:cw_core/db/sqlite.dart';
import 'package:cw_core/wallet_info.dart';
+import 'package:cw_core/utils/tor/abstract.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -86,12 +87,16 @@ Future<void> runAppWithZone({Key? topLevelKey}) async {
return true;
};
+
await FlutterDaemon().unmarkBackgroundSync();
+ await initDb();
+
try {
CakeTor.instance = await CakeTorInstance.getInstance();
} catch (e) {
printV("Failed to initialize tor: $e");
}
+
await initializeAppAtRoot();
if (kDebugMode) {
@@ -164,22 +169,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
CakeHive.registerAdapter(AddressInfoAdapter());
}
- if (!CakeHive.isAdapterRegistered(WalletInfo.typeId)) {
- CakeHive.registerAdapter(WalletInfoAdapter());
- }
-
- if (!CakeHive.isAdapterRegistered(DERIVATION_TYPE_TYPE_ID)) {
- CakeHive.registerAdapter(DerivationTypeAdapter());
- }
-
- if (!CakeHive.isAdapterRegistered(DERIVATION_INFO_TYPE_ID)) {
- CakeHive.registerAdapter(DerivationInfoAdapter());
- }
-
- if (!CakeHive.isAdapterRegistered(HARDWARE_WALLET_TYPE_TYPE_ID)) {
- CakeHive.registerAdapter(HardwareWalletTypeAdapter());
- }
-
if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) {
CakeHive.registerAdapter(WalletTypeAdapter());
}
@@ -227,6 +216,7 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
CakeHive.registerAdapter(TronTokenAdapter());
}
+ await performHiveMigration();
final secureStorage = secureStorageShared;
final transactionDescriptionsBoxKey =
@@ -242,7 +232,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
encryptionKey: transactionDescriptionsBoxKey);
final trades = await CakeHive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
- final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
final templates = await CakeHive.openBox<Template>(Template.boxName);
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
final anonpayInvoiceInfo = await CakeHive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
@@ -259,7 +248,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
sharedPreferences: await SharedPreferences.getInstance(),
nodes: nodes,
powNodes: powNodes,
- walletInfoSource: walletInfoSource,
contactSource: contacts,
tradesSource: trades,
ordersSource: orders,
@@ -281,7 +269,6 @@ Future<void> initialSetup({
required SharedPreferences sharedPreferences,
required Box<Node> nodes,
required Box<Node> powNodes,
- required Box<WalletInfo> walletInfoSource,
required Box<Contact> contactSource,
required Box<Trade> tradesSource,
required Box<Order> ordersSource,
@@ -294,21 +281,19 @@ Future<void> initialSetup({
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
required Box<PayjoinSession> payjoinSessionSource,
required Box<HavenSeedStore> havenSeedStore,
- int initialMigrationVersion = 15,
+ required int initialMigrationVersion,
}) async {
LanguageService.loadLocaleList();
await defaultSettingsMigration(
secureStorage: secureStorage,
version: initialMigrationVersion,
sharedPreferences: sharedPreferences,
- walletInfoSource: walletInfoSource,
contactSource: contactSource,
tradeSource: tradesSource,
nodes: nodes,
powNodes: powNodes,
havenSeedStore: havenSeedStore);
await setup(
- walletInfoSource: walletInfoSource,
nodeSource: nodes,
powNodeSource: powNodes,
contactSource: contactSource,
diff --git a/lib/monero/cw_monero.dart b/lib/monero/cw_monero.dart
index 8de8f90..643eb30 100644
--- a/lib/monero/cw_monero.dart
+++ b/lib/monero/cw_monero.dart
@@ -346,9 +346,8 @@ class CWMonero extends Monero {
}
@override
- WalletService createMoneroWalletService(
- Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) =>
- MoneroWalletService(walletInfoSource, unspentCoinSource);
+ WalletService createMoneroWalletService(Box<UnspentCoinsInfo> unspentCoinSource) =>
+ MoneroWalletService(unspentCoinSource);
@override
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
@@ -416,9 +415,9 @@ class CWMonero extends Monero {
}
@override
- void setLedgerConnection(Object wallet, ledger.LedgerConnection connection) {
+ Future<void> setLedgerConnection(Object wallet, ledger.LedgerConnection connection) async {
final moneroWallet = wallet as MoneroWallet;
- moneroWallet.setLedgerConnection(connection);
+ await moneroWallet.setLedgerConnection(connection);
}
@override
diff --git a/lib/nano/cw_nano.dart b/lib/nano/cw_nano.dart
index 463e19d..c3a3730 100644
--- a/lib/nano/cw_nano.dart
+++ b/lib/nano/cw_nano.dart
@@ -75,8 +75,8 @@ class CWNano extends Nano {
}
@override
- WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) {
- return NanoWalletService(walletInfoSource, isDirect);
+ WalletService createNanoWalletService(bool isDirect) {
+ return NanoWalletService(isDirect);
}
@override
diff --git a/lib/polygon/cw_polygon.dart b/lib/polygon/cw_polygon.dart
index e9bf9a9..8c8c2a7 100644
--- a/lib/polygon/cw_polygon.dart
+++ b/lib/polygon/cw_polygon.dart
@@ -4,8 +4,8 @@ class CWPolygon extends Polygon {
@override
List<String> getPolygonWordList(String language) => EVMChainMnemonics.englishWordlist;
- WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
- PolygonWalletService(walletInfoSource, isDirect, client: PolygonClient());
+ WalletService createPolygonWalletService(bool isDirect) =>
+ PolygonWalletService(isDirect, client: PolygonClient());
@override
WalletCredentials createPolygonNewWalletCredentials({
@@ -206,16 +206,16 @@ class CWPolygon extends Polygon {
);
@override
- void setHardwareWalletService(WalletBase wallet, HardwareWalletService service) {
+ Future<void> setHardwareWalletService(WalletBase wallet, HardwareWalletService service) async {
if (service is EVMChainLedgerService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials).setLedgerConnection(
- service.ledgerConnection, wallet.walletInfo.derivationInfo?.derivationPath);
+ service.ledgerConnection, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
} else if (service is EVMChainBitboxService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmBitboxCredentials)
- .setBitbox(service.manager, wallet.walletInfo.derivationInfo?.derivationPath);
+ .setBitbox(service.manager, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
} else if (service is EVMChainTrezorService) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmTrezorCredentials)
- .setTrezorConnect(service.connect, wallet.walletInfo.derivationInfo?.derivationPath);
+ .setTrezorConnect(service.connect, (await wallet.walletInfo.getDerivationInfo()).derivationPath);
}
}
diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart
index b95bb7e..cdbe39a 100644
--- a/lib/reactions/on_authentication_state_change.dart
+++ b/lib/reactions/on_authentication_state_change.dart
@@ -43,7 +43,7 @@ void startAuthenticationStateChange(
if (state == AuthenticationState.installed &&
!SettingsStoreBase.walletPasswordDirectInput) {
try {
- if (!requireHardwareWalletConnection()) await loadCurrentWallet();
+ if (!(await requireHardwareWalletConnection())) await loadCurrentWallet();
} catch (error, stack) {
loginError = error;
await ExceptionHandler.resetLastPopupDate();
@@ -56,7 +56,7 @@ void startAuthenticationStateChange(
if ([AuthenticationState.allowed, AuthenticationState.allowedCreate]
.contains(state)) {
if (state == AuthenticationState.allowed &&
- requireHardwareWalletConnection()) {
+ (await requireHardwareWalletConnection())) {
await navigatorKey.currentState!.pushNamedAndRemoveUntil(
Routes.connectDevices,
(route) => false,
diff --git a/lib/reactions/on_current_wallet_change.dart b/lib/reactions/on_current_wallet_change.dart
index eed86e0..53da945 100644
--- a/lib/reactions/on_current_wallet_change.dart
+++ b/lib/reactions/on_current_wallet_change.dart
@@ -99,9 +99,7 @@ void startCurrentWalletChangeReaction(
if (wallet.walletInfo.address.isEmpty) {
wallet.walletInfo.address = wallet.walletAddresses.address;
- if (wallet.walletInfo.isInBox) {
- await wallet.walletInfo.save();
- }
+ await wallet.walletInfo.save();
}
} catch (e) {
printV(e.toString());
diff --git a/lib/solana/cw_solana.dart b/lib/solana/cw_solana.dart
index ca001bb..a4cd8ee 100644
--- a/lib/solana/cw_solana.dart
+++ b/lib/solana/cw_solana.dart
@@ -4,8 +4,8 @@ class CWSolana extends Solana {
@override
List<String> getSolanaWordList(String language) => SolanaMnemonics.englishWordlist;
- WalletService createSolanaWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
- SolanaWalletService(walletInfoSource, isDirect);
+ WalletService createSolanaWalletService(bool isDirect) =>
+ SolanaWalletService(isDirect);
@override
WalletCredentials createSolanaNewWalletCredentials({
diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart
index cf4486a..d9149df 100644
--- a/lib/src/screens/contact/contact_list_page.dart
+++ b/lib/src/screens/contact/contact_list_page.dart
@@ -17,6 +17,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
+import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class ContactListPage extends BasePage {
@@ -150,7 +151,9 @@ class _ContactPageBodyState extends State<ContactPageBody> with SingleTickerProv
child: TabBarView(
controller: _tabController,
children: [
- _buildWalletContacts(context),
+ Observer(
+ builder: (final BuildContext context) => _buildWalletContacts(context),
+ ),
ContactListBody(
contactListViewModel: widget.contactListViewModel,
tabController: _tabController,
diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart
index be6a4cc..2b48976 100644
--- a/lib/src/screens/new_wallet/new_wallet_page.dart
+++ b/lib/src/screens/new_wallet/new_wallet_page.dart
@@ -351,7 +351,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
_formProcessing = false;
return;
}
- if (_walletNewVM.nameExists(_walletNewVM.name)) {
+ if (await _walletNewVM.nameExists(_walletNewVM.name)) {
await showPopUp<void>(
context: context,
builder: (_) {
diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart
index ef2fd3e..a50384c 100644
--- a/lib/src/screens/restore/wallet_restore_page.dart
+++ b/lib/src/screens/restore/wallet_restore_page.dart
@@ -258,7 +258,7 @@ class WalletRestorePage extends BasePage {
return;
}
- if (walletRestoreViewModel.nameExists(name)) {
+ if (await walletRestoreViewModel.nameExists(name)) {
showNameExistsAlert(formContext!);
_formProcessing = false;
return;
diff --git a/lib/src/screens/settings/other_settings_page.dart b/lib/src/screens/settings/other_settings_page.dart
index b40cbeb..cbd151e 100644
--- a/lib/src/screens/settings/other_settings_page.dart
+++ b/lib/src/screens/settings/other_settings_page.dart
@@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
+import 'package:cake_wallet/src/screens/dev/moneroc_cache_debug.dart';
import 'package:cake_wallet/src/screens/settings/widgets/setting_priority_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
@@ -11,6 +12,7 @@ import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
+import 'package:cw_core/db/sqlite.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -144,6 +146,16 @@ class OtherSettingsPage extends BasePage {
handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs),
),
+ if (FeatureFlag.hasDevOptions)
+ SettingsCellWithArrow(
+ title: '[dev] browse sqlite db',
+ handler: (BuildContext context) async {
+ final data = await dumpDb();
+ Navigator.of(context).push(
+ MaterialPageRoute(builder: (context) => JsonExplorerPage(data: data, title: 'sqlite db')),
+ );
+ }
+ ),
Spacer(),
SettingsVersionCell(
title: S.of(context).version(_otherSettingsViewModel.currentVersion),
diff --git a/lib/src/screens/wallet/wallet_edit_page.dart b/lib/src/screens/wallet/wallet_edit_page.dart
index 13cc8dc..8e8fc79 100644
--- a/lib/src/screens/wallet/wallet_edit_page.dart
+++ b/lib/src/screens/wallet/wallet_edit_page.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/core/wallet_name_validator.dart';
import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
@@ -10,6 +12,7 @@ import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
+import 'package:cw_core/utils/print_verbose.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
@@ -86,7 +89,7 @@ class WalletEditPage extends BasePage {
onPressed: () async {
if (_formKey.currentState?.validate() ?? false) {
if (!pageArguments.isWalletGroup &&
- pageArguments.walletNewVM!
+ await pageArguments.walletNewVM!
.nameExists(walletEditViewModel.newName)) {
showPopUp<void>(
context: context,
@@ -217,9 +220,12 @@ class WalletEditPage extends BasePage {
}
Future<void> hideProgressText() async {
- await Future.delayed(Duration(milliseconds: 50), () {
- _progressBar?.dismiss();
- _progressBar = null;
- });
+ try {
+ await Future.delayed(Duration(milliseconds: 250));
+ await _progressBar?.dismiss();
+ } catch (e) {
+ printV(e);
+ }
+ _progressBar = null;
}
}
diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart
index 42000a6..f4730a5 100644
--- a/lib/src/screens/wallet_list/wallet_list_page.dart
+++ b/lib/src/screens/wallet_list/wallet_list_page.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/new_wallet_arguments.dart';
@@ -27,6 +29,7 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/currency_for_wallet_type.dart';
import 'package:cw_core/wallet_info.dart';
+import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -40,17 +43,26 @@ class WalletListPage extends BasePage {
final WalletListViewModel walletListViewModel;
final AuthService authService;
- final Function(BuildContext)? onWalletLoaded;
+ final Future<void> Function(BuildContext)? onWalletLoaded;
@override
String get title => S.current.wallets;
@override
- Widget body(BuildContext context) => WalletListBody(
+ Widget body(BuildContext context) => Observer(
+ builder: (_) {
+ if (walletListViewModel.singleWalletsList.isEmpty && walletListViewModel.multiWalletGroups.isEmpty) {
+ return Center(
+ child: CircularProgressIndicator(),
+ );
+ }
+ return WalletListBody(
walletListViewModel: walletListViewModel,
authService: authService,
onWalletLoaded: onWalletLoaded ?? (context) => Navigator.of(context).pop(),
);
+ }
+ );
@override
Widget trailing(BuildContext context) {
@@ -459,7 +471,7 @@ class WalletListBodyState extends State<WalletListBody> {
try {
final requireHardwareWalletConnection =
- widget.walletListViewModel.requireHardwareWalletConnection(wallet);
+ await widget.walletListViewModel.requireHardwareWalletConnection(wallet);
if (requireHardwareWalletConnection) {
bool didConnect = false;
await Navigator.of(context).pushNamed(
@@ -489,22 +501,20 @@ class WalletListBodyState extends State<WalletListBody> {
buttonAction: () => Navigator.of(context).pop()),
);
}
-
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
await widget.walletListViewModel.loadWallet(wallet);
- await hideProgressText();
// only pop the wallets route in mobile as it will go back to dashboard page
// in desktop platforms the navigation tree is different
if (responsiveLayoutUtil.shouldRenderMobileUI) {
- WidgetsBinding.instance.addPostFrameCallback((_) {
- if (this.mounted) {
- if (requireHardwareWalletConnection) {
- Navigator.of(context).pop();
- }
- widget.onWalletLoaded.call(context);
- }
- });
+ // await Future.delayed(Duration(seconds: 1));
+ // if (!this.mounted) return;
+ if (!context.mounted) return;
+ if (requireHardwareWalletConnection) {
+ Navigator.of(context).pop();
+ }
+ await widget.onWalletLoaded.call(context);
}
+ unawaited(hideProgressText());
} catch (e) {
await ExceptionHandler.resetLastPopupDate();
final err = e.toString();
diff --git a/lib/src/widgets/bottom_sheet/wallet_switcher_bottom_sheet.dart b/lib/src/widgets/bottom_sheet/wallet_switcher_bottom_sheet.dart
index 1cab364..68de145 100644
--- a/lib/src/widgets/bottom_sheet/wallet_switcher_bottom_sheet.dart
+++ b/lib/src/widgets/bottom_sheet/wallet_switcher_bottom_sheet.dart
@@ -52,76 +52,79 @@ class _WalletSwitcherContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Observer(
- builder: (_) {
- final wallets = viewModel.getWallets(filterWalletType);
-
- if (viewModel.isProcessing) {
- return Container(
- height: 200,
- child: Center(
- child: CircularProgressIndicator(
- color: Theme.of(context).colorScheme.primary,
+ return FutureBuilder(
+ future: viewModel.getWallets(filterWalletType),
+ builder: (context, snapshot) => Observer(
+ builder: (_) {
+ final List<WalletInfo> wallets = (snapshot.data ?? []);
+
+ if (viewModel.isProcessing) {
+ return Container(
+ height: 200,
+ child: Center(
+ child: CircularProgressIndicator(
+ color: Theme.of(context).colorScheme.primary,
+ ),
),
- ),
- );
- }
-
- return Container(
- height: 400,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Expanded(
- child: StandardList(
- itemCount: wallets.length,
- itemBuilder: (context, index) {
- final wallet = wallets[index];
-
- return InkWell(
- onTap: () {
- viewModel.selectWallet(wallet);
- Navigator.of(context).pop();
- },
- borderRadius: BorderRadius.circular(12),
- child: Container(
- margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
- decoration: BoxDecoration(
- color: Theme.of(context).colorScheme.surfaceContainer,
- borderRadius: BorderRadius.circular(16),
- ),
- height: 60,
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
- child: Row(
- children: [
- Image.asset(
- walletTypeToCryptoCurrency(wallet.type).iconPath!,
- width: 32,
- height: 32,
- ),
- const SizedBox(width: 16),
- Text(
- wallet.name,
- style: Theme.of(context).textTheme.bodyMedium!.copyWith(
- fontSize: 18,
- fontWeight: FontWeight.w700,
- color: Theme.of(context).colorScheme.onSurface,
- letterSpacing: 0.0,
- ),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- ],
+ );
+ }
+
+ return Container(
+ height: 400,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: StandardList(
+ itemCount: wallets.length,
+ itemBuilder: (context, index) {
+ final wallet = wallets[index];
+
+ return InkWell(
+ onTap: () {
+ viewModel.selectWallet(wallet);
+ Navigator.of(context).pop();
+ },
+ borderRadius: BorderRadius.circular(12),
+ child: Container(
+ margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.surfaceContainer,
+ borderRadius: BorderRadius.circular(16),
+ ),
+ height: 60,
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
+ child: Row(
+ children: [
+ Image.asset(
+ walletTypeToCryptoCurrency(wallet.type).iconPath!,
+ width: 32,
+ height: 32,
+ ),
+ const SizedBox(width: 16),
+ Text(
+ wallet.name,
+ style: Theme.of(context).textTheme.bodyMedium!.copyWith(
+ fontSize: 18,
+ fontWeight: FontWeight.w700,
+ color: Theme.of(context).colorScheme.onSurface,
+ letterSpacing: 0.0,
+ ),
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ ),
+ ],
+ ),
),
- ),
- );
- },
+ );
+ },
+ ),
),
- ),
- ],
- ),
- );
- },
+ ],
+ ),
+ );
+ },
+ ),
);
}
}
diff --git a/lib/store/app_store.dart b/lib/store/app_store.dart
index 44f1807..c3e7cc4 100644
--- a/lib/store/app_store.dart
+++ b/lib/store/app_store.dart
@@ -55,8 +55,8 @@ abstract class AppStoreBase with Store {
getIt.get<WalletKitService>().create();
await getIt.get<WalletKitService>().init();
}
- getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
- getIt
+ await getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
+ await getIt
.get<SharedPreferences>()
.setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
}
diff --git a/lib/store/yat/yat_store.dart b/lib/store/yat/yat_store.dart
index 6b73c62..860eece 100644
--- a/lib/store/yat/yat_store.dart
+++ b/lib/store/yat/yat_store.dart
@@ -243,9 +243,7 @@ abstract class YatStoreBase with Store {
walletInfo!.yatEid = emoji;
- if (walletInfo!.isInBox) {
- walletInfo!.save();
- }
+ walletInfo!.save();
} catch (e) {
printV(e.toString());
}
diff --git a/lib/tron/cw_tron.dart b/lib/tron/cw_tron.dart
index 395129b..9cc52e2 100644
--- a/lib/tron/cw_tron.dart
+++ b/lib/tron/cw_tron.dart
@@ -5,8 +5,8 @@ class CWTron extends Tron {
List<String> getTronWordList(String language) => EVMChainMnemonics.englishWordlist;
@override
- WalletService createTronWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
- TronWalletService(walletInfoSource, client: TronClient(), isDirect: isDirect);
+ WalletService createTronWalletService(bool isDirect) =>
+ TronWalletService(client: TronClient(), isDirect: isDirect);
@override
WalletCredentials createTronNewWalletCredentials({
diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart
index 0950b4f..5733f64 100644
--- a/lib/utils/exception_handler.dart
+++ b/lib/utils/exception_handler.dart
@@ -290,6 +290,8 @@ class ExceptionHandler {
"core/key_service.dart:14",
"Wallet is null",
"Wrong Device Status: 0x5515 (UNKNOWN)",
+
+ "FocusScopeNode was used after being disposed",
];
static Future<void> _addDeviceInfo(File file) async {
diff --git a/lib/utils/token_utilities.dart b/lib/utils/token_utilities.dart
index c9a8182..024c168 100644
--- a/lib/utils/token_utilities.dart
+++ b/lib/utils/token_utilities.dart
@@ -10,11 +10,10 @@ import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
class TokenUtilities {
- static Future<List<Erc20Token>> loadAllUniqueEvmTokens(
- Box<WalletInfo> walletInfoSource,
- ) async {
- final evmWallets = walletInfoSource.values.where(
- (w) => isEVMCompatibleChain(w.type),
+ static Future<List<Erc20Token>> loadAllUniqueEvmTokens() async {
+ final allWi = await WalletInfo.getAll();
+ final evmWallets = allWi.where(
+ (w) => isEVMCompatibleChain(w.type),
);
final seen = <String>{};
@@ -35,10 +34,9 @@ class TokenUtilities {
return unique;
}
- static Future<List<SPLToken>> loadAllUniqueSolTokens(
- Box<WalletInfo> walletInfoSource,
- ) async {
- final solWallets = walletInfoSource.values.where(
+ static Future<List<SPLToken>> loadAllUniqueSolTokens() async {
+ final allWi = await WalletInfo.getAll();
+ final solWallets = allWi.where(
(w) => w.type == WalletType.solana,
);
@@ -57,10 +55,9 @@ class TokenUtilities {
return unique;
}
- static Future<List<TronToken>> loadAllUniqueTronTokens(
- Box<WalletInfo> walletInfoSource,
- ) async {
- final tronWallets = walletInfoSource.values.where(
+ static Future<List<TronToken>> loadAllUniqueTronTokens() async {
+ final allWi = await WalletInfo.getAll();
+ final tronWallets = allWi.where(
(w) => w.type == WalletType.tron,
);
@@ -82,7 +79,6 @@ class TokenUtilities {
/// - Tron: match by contractAddress
static Future<CryptoCurrency?> findTokenByAddress({
required WalletType walletType,
- required Box<WalletInfo> walletInfoSource,
required String address,
}) async {
final lower = address.toLowerCase();
@@ -90,19 +86,19 @@ class TokenUtilities {
case WalletType.ethereum:
case WalletType.polygon:
case WalletType.base:
- final tokens = await loadAllUniqueEvmTokens(walletInfoSource);
+ final tokens = await loadAllUniqueEvmTokens();
for (final t in tokens) {
if (t.contractAddress.toLowerCase() == lower) return t;
}
return null;
case WalletType.solana:
- final solTokens = await loadAllUniqueSolTokens(walletInfoSource);
+ final solTokens = await loadAllUniqueSolTokens();
for (final t in solTokens) {
if (t.mintAddress.toLowerCase() == lower) return t;
}
return null;
case WalletType.tron:
- final tronTokens = await loadAllUniqueTronTokens(walletInfoSource);
+ final tronTokens = await loadAllUniqueTronTokens();
for (final t in tronTokens) {
if (t.contractAddress.toLowerCase() == lower) return t;
}
diff --git a/lib/view_model/contact_list/contact_list_view_model.dart b/lib/view_model/contact_list/contact_list_view_model.dart
index 27aee91..7f5ec99 100644
--- a/lib/view_model/contact_list/contact_list_view_model.dart
+++ b/lib/view_model/contact_list/contact_list_view_model.dart
@@ -22,16 +22,22 @@ class ContactListViewModel = ContactListViewModelBase with _$ContactListViewMode
abstract class ContactListViewModelBase with Store {
ContactListViewModelBase(
- this.contactSource, this.walletInfoSource, this._currency, this.settingsStore)
+ this.contactSource, List<WalletInfo> wallets, this._currency, this.settingsStore)
: contacts = ObservableList<ContactRecord>(),
- walletContacts = [],
isAutoGenerateEnabled =
settingsStore.autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.enabled {
- walletInfoSource.values.forEach((info) {
+ unawaited(_init());
+ }
+
+ Future<void> _init() async {
+ final walletInfos = await WalletInfo.getAll();
+ for (final info in walletInfos) {
+ final addressInfos = await info.getAddressInfos();
+ final addresses = await info.getAddresses();
if ([WalletType.monero, WalletType.wownero, WalletType.haven].contains(info.type) &&
- info.addressInfos != null) {
- for (var key in info.addressInfos!.keys) {
- final value = info.addressInfos![key];
+ addressInfos.isNotEmpty) {
+ for (var key in addressInfos.keys) {
+ final value = addressInfos[key];
final address = value?.first;
if (address != null) {
final name = _createName(info.name, address.label, key: key);
@@ -42,7 +48,7 @@ abstract class ContactListViewModelBase with Store {
));
}
}
- } else if (info.addresses?.isNotEmpty == true && info.addresses!.length > 1) {
+ } else if (addresses.isNotEmpty == true && addresses.length > 1) {
if ([WalletType.monero, WalletType.wownero, WalletType.haven, WalletType.decred]
.contains(info.type)) {
final address = info.address;
@@ -53,7 +59,7 @@ abstract class ContactListViewModelBase with Store {
walletTypeToCryptoCurrency(info.type),
));
} else {
- info.addresses!.forEach((address, label) {
+ addresses.forEach((address, label) {
if (label.isEmpty) {
return;
Why this scored 49/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.