Skip to content

Commit 7687618

Browse files
authored
feat: initial hive -> SQLite (#2502)
* feat: initial hive -> SQLite Includes migration script and initial work done to remove dependency on hive generators. Also contains some refactoring to make sync code async. Features new dev screen that lists all SQLite tables Aspects that need testing: - backups (from this version, and from previous versions as well) - wallet loading / wallet list - almost everything else - renaming - deletion - sorting in wallet list - wallet groups - wallet seed/keys - wallet switching - wallet creation / restore - all methods - wallet address page - hardware wallet connection (and prompts from mall screens) - contacts - advanced settings in wallet creation - derivation paths - some minor wownero fixes - base, hardware wallets * fix: build errors * fix: Bad state: No element in backup restore * address comments from review * fix: HardwareWalletType
1 parent 7185259 commit 7687618

File tree

121 files changed

+2624
-918
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+2624
-918
lines changed

.github/workflows/pr_test_build_linux.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,8 @@ jobs:
308308
rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet
309309
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
310310
- name: Test [cw_monero]
311-
timeout-minutes: 2
312-
run: cd cw_monero && flutter test
311+
timeout-minutes: 15
312+
run: cd cw_monero && flutter test --verbose
313313
- name: Stop screen recording, encrypt and upload
314314
if: always()
315315
run: |

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ RUN set -o xtrace \
5959
ffmpeg network-manager x11-utils xvfb psmisc \
6060
# extra linux dependencies so flutter doesn't complain
6161
mesa-utils \
62+
# database
63+
libsqlite3-0 libsqlite3-dev \
6264
# aarch64-linux-gnu dependencies
6365
g++-aarch64-linux-gnu gcc-aarch64-linux-gnu \
6466
# x86_64-linux-gnu dependencies

cw_base/lib/base_wallet.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class BaseWallet extends EVMChainWallet {
2222
BaseWallet({
2323
required super.walletInfo,
2424
required super.password,
25+
required super.derivationInfo,
2526
super.mnemonic,
2627
super.initialBalance,
2728
super.privateKey,
@@ -150,6 +151,7 @@ class BaseWallet extends EVMChainWallet {
150151

151152
return BaseWallet(
152153
walletInfo: walletInfo,
154+
derivationInfo: await walletInfo.getDerivationInfo(),
153155
password: password,
154156
mnemonic: keysData.mnemonic,
155157
privateKey: keysData.privateKey,

cw_base/lib/base_wallet_service.dart

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import 'package:cw_base/base_mnemonics_exception.dart';
1111

1212
class BaseWalletService extends EVMChainWalletService<BaseWallet> {
1313
BaseWalletService(
14-
super.walletInfoSource,
1514
super.isDirect, {
1615
required this.client,
1716
});
@@ -29,6 +28,7 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
2928

3029
final wallet = BaseWallet(
3130
walletInfo: credentials.walletInfo!,
31+
derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
3232
mnemonic: mnemonic,
3333
password: credentials.password!,
3434
passphrase: credentials.passphrase,
@@ -44,8 +44,10 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
4444

4545
@override
4646
Future<BaseWallet> openWallet(String name, String password) async {
47-
final walletInfo =
48-
walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
47+
final walletInfo = await WalletInfo.get(name, getType());
48+
if (walletInfo == null) {
49+
throw Exception('Wallet not found');
50+
}
4951

5052
try {
5153
final wallet = await BaseWallet.open(
@@ -84,6 +86,7 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
8486
password: credentials.password!,
8587
privateKey: credentials.privateKey,
8688
walletInfo: credentials.walletInfo!,
89+
derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
8790
client: client,
8891
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
8992
);
@@ -97,14 +100,17 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
97100
@override
98101
Future<BaseWallet> restoreFromHardwareWallet(
99102
EVMChainRestoreWalletFromHardware credentials) async {
100-
credentials.walletInfo!.derivationInfo = DerivationInfo(
101-
derivationType: DerivationType.bip39,
102-
derivationPath: "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0");
103+
final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
104+
derivationInfo.derivationType = DerivationType.bip39;
105+
derivationInfo.derivationPath = "m/44'/60'/${credentials.hwAccountData.accountIndex}'/0/0";
106+
await derivationInfo.save();
103107
credentials.walletInfo!.hardwareWalletType = credentials.hardwareWalletType;
104108
credentials.walletInfo!.address = credentials.hwAccountData.address;
109+
await credentials.walletInfo!.save();
105110

106111
final wallet = BaseWallet(
107112
walletInfo: credentials.walletInfo!,
113+
derivationInfo: derivationInfo,
108114
password: credentials.password!,
109115
client: client,
110116
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -128,6 +134,7 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
128134
password: credentials.password!,
129135
mnemonic: credentials.mnemonic,
130136
walletInfo: credentials.walletInfo!,
137+
derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
131138
passphrase: credentials.passphrase,
132139
client: client,
133140
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -142,8 +149,10 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
142149

143150
@override
144151
Future<void> rename(String currentName, String password, String newName) async {
145-
final currentWalletInfo = walletInfoSource.values
146-
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
152+
final currentWalletInfo = await WalletInfo.get(currentName, getType());
153+
if (currentWalletInfo == null) {
154+
throw Exception('Wallet not found');
155+
}
147156
final currentWallet = await BaseWallet.open(
148157
password: password,
149158
name: currentName,
@@ -158,6 +167,6 @@ class BaseWalletService extends EVMChainWalletService<BaseWallet> {
158167
newWalletInfo.id = WalletBase.idFor(newName, getType());
159168
newWalletInfo.name = newName;
160169

161-
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
170+
newWalletInfo.save();
162171
}
163172
}

cw_bitcoin/lib/bitcoin_wallet.dart

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
4747
BitcoinWalletBase({
4848
required String password,
4949
required WalletInfo walletInfo,
50+
required DerivationInfo derivationInfo,
5051
required Box<UnspentCoinsInfo> unspentCoinsInfo,
5152
required Box<PayjoinSession> payjoinBox,
5253
required EncryptionFileUtils encryptionFileUtils,
@@ -69,6 +70,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
6970
xpub: xpub,
7071
password: password,
7172
walletInfo: walletInfo,
73+
derivationInfo: derivationInfo,
7274
unspentCoinsInfo: unspentCoinsInfo,
7375
network: networkParam == null
7476
? BitcoinNetwork.mainnet
@@ -133,7 +135,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
133135
}) async {
134136
late Uint8List seedBytes;
135137

136-
switch (walletInfo.derivationInfo?.derivationType) {
138+
final derivationInfo = await walletInfo.getDerivationInfo();
139+
140+
switch (derivationInfo.derivationType) {
137141
case DerivationType.bip39:
138142
seedBytes = await bip39.mnemonicToSeed(
139143
mnemonic,
@@ -152,6 +156,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
152156
passphrase: passphrase ?? "",
153157
password: password,
154158
walletInfo: walletInfo,
159+
derivationInfo: derivationInfo,
155160
unspentCoinsInfo: unspentCoinsInfo,
156161
initialAddresses: initialAddresses,
157162
initialSilentAddresses: initialSilentAddresses,
@@ -212,20 +217,21 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
212217
);
213218
}
214219

215-
walletInfo.derivationInfo ??= DerivationInfo();
220+
final derivationInfo = await walletInfo.getDerivationInfo();
216221

217222
// set the default if not present:
218-
walletInfo.derivationInfo!.derivationPath ??=
223+
derivationInfo.derivationPath ??=
219224
snp?.derivationPath ?? electrum_path;
220-
walletInfo.derivationInfo!.derivationType ??=
225+
derivationInfo.derivationType ??=
221226
snp?.derivationType ?? DerivationType.electrum;
227+
await derivationInfo.save();
222228

223229
Uint8List? seedBytes = null;
224230
final mnemonic = keysData.mnemonic;
225231
final passphrase = keysData.passphrase;
226232

227233
if (mnemonic != null) {
228-
switch (walletInfo.derivationInfo!.derivationType) {
234+
switch (derivationInfo.derivationType) {
229235
case DerivationType.electrum:
230236
seedBytes =
231237
await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
@@ -246,6 +252,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
246252
password: password,
247253
passphrase: passphrase,
248254
walletInfo: walletInfo,
255+
derivationInfo: derivationInfo,
249256
unspentCoinsInfo: unspentCoinsInfo,
250257
initialAddresses: snp?.addresses,
251258
initialSilentAddresses: snp?.silentAddresses,
@@ -484,7 +491,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
484491
: null;
485492
final index = addressEntry?.index ?? 0;
486493
final isChange = addressEntry?.isHidden == true ? 1 : 0;
487-
final accountPath = walletInfo.derivationInfo?.derivationPath;
494+
final derivationInfo = await walletInfo.getDerivationInfo();
495+
final accountPath = derivationInfo.derivationPath;
488496
final derivationPath =
489497
accountPath != null ? "$accountPath/$isChange/$index" : null;
490498

cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
1616
walletInfo: walletInfo,
1717
password: password,
1818
passphrase: passphrase,
19+
derivationInfo: DerivationInfo(
20+
derivationType: derivationType,
21+
derivationPath: derivationPath,
22+
),
1923
);
2024

2125
final String? mnemonic;

cw_bitcoin/lib/bitcoin_wallet_service.dart

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ class BitcoinWalletService extends WalletService<
2323
BitcoinRestoreWalletFromSeedCredentials,
2424
BitcoinWalletFromKeysCredentials,
2525
BitcoinRestoreWalletFromHardware> {
26-
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource,
26+
BitcoinWalletService(this.unspentCoinsInfoSource,
2727
this.payjoinSessionSource, this.isDirect);
2828

29-
final Box<WalletInfo> walletInfoSource;
3029
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
3130
final Box<PayjoinSession> payjoinSessionSource;
3231
final bool isDirect;
@@ -40,7 +39,13 @@ class BitcoinWalletService extends WalletService<
4039
credentials.walletInfo?.network = network.value;
4140

4241
final String mnemonic;
43-
switch ( credentials.walletInfo?.derivationInfo?.derivationType) {
42+
final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
43+
derivationInfo.derivationType = credentials.derivationInfo?.derivationType ?? derivationInfo.derivationType;
44+
derivationInfo.derivationPath = credentials.derivationInfo?.derivationPath ?? derivationInfo.derivationPath;
45+
derivationInfo.description = credentials.derivationInfo?.description ?? derivationInfo.description;
46+
derivationInfo.scriptType = credentials.derivationInfo?.scriptType ?? derivationInfo.scriptType;
47+
await derivationInfo.save();
48+
switch (derivationInfo.derivationType) {
4449
case DerivationType.bip39:
4550
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
4651

@@ -51,6 +56,7 @@ class BitcoinWalletService extends WalletService<
5156
mnemonic = await generateElectrumMnemonic();
5257
break;
5358
}
59+
await derivationInfo.save();
5460

5561
final wallet = await BitcoinWalletBase.create(
5662
mnemonic: mnemonic,
@@ -75,8 +81,10 @@ class BitcoinWalletService extends WalletService<
7581

7682
@override
7783
Future<BitcoinWallet> openWallet(String name, String password) async {
78-
final walletInfo = walletInfoSource.values
79-
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
84+
final walletInfo = await WalletInfo.get(name, getType());
85+
if (walletInfo == null) {
86+
throw Exception('Wallet not found');
87+
}
8088
try {
8189
final wallet = await BitcoinWalletBase.open(
8290
password: password,
@@ -107,9 +115,11 @@ class BitcoinWalletService extends WalletService<
107115
@override
108116
Future<void> remove(String wallet) async {
109117
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
110-
final walletInfo = walletInfoSource.values
111-
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
112-
await walletInfoSource.delete(walletInfo.key);
118+
final walletInfo = await WalletInfo.get(wallet, getType());
119+
if (walletInfo == null) {
120+
throw Exception('Wallet not found');
121+
}
122+
await WalletInfo.delete(walletInfo);
113123

114124
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where(
115125
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList();
@@ -123,8 +133,10 @@ class BitcoinWalletService extends WalletService<
123133

124134
@override
125135
Future<void> rename(String currentName, String password, String newName) async {
126-
final currentWalletInfo = walletInfoSource.values
127-
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
136+
final currentWalletInfo = await WalletInfo.get(currentName, getType());
137+
if (currentWalletInfo == null) {
138+
throw Exception('Wallet not found');
139+
}
128140
final currentWallet = await BitcoinWalletBase.open(
129141
password: password,
130142
name: currentName,
@@ -141,23 +153,26 @@ class BitcoinWalletService extends WalletService<
141153
newWalletInfo.id = WalletBase.idFor(newName, getType());
142154
newWalletInfo.name = newName;
143155

144-
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
156+
await newWalletInfo.save();
145157
}
146158

147159
@override
148160
Future<BitcoinWallet> restoreFromHardwareWallet(BitcoinRestoreWalletFromHardware credentials,
149161
{bool? isTestnet}) async {
150162
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
151163
credentials.walletInfo?.network = network.value;
152-
credentials.walletInfo?.derivationInfo?.derivationPath =
164+
final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
165+
derivationInfo.derivationPath =
153166
credentials.hwAccountData.derivationPath;
154167

155168
final xpub = convertZpubToXpub(credentials.hwAccountData.xpub!);
156169

170+
await credentials.walletInfo!.save();
157171
final wallet = await BitcoinWallet(
158172
password: credentials.password!,
159173
xpub: xpub,
160174
walletInfo: credentials.walletInfo!,
175+
derivationInfo: derivationInfo,
161176
unspentCoinsInfo: unspentCoinsInfoSource,
162177
networkParam: network,
163178
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
@@ -180,6 +195,7 @@ class BitcoinWalletService extends WalletService<
180195
password: credentials.password!,
181196
xpub: xpub,
182197
walletInfo: credentials.walletInfo!,
198+
derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
183199
unspentCoinsInfo: unspentCoinsInfoSource,
184200
networkParam: network,
185201
encryptionFileUtils: encryptionFileUtilsFor(isDirect),

cw_bitcoin/lib/electrum_wallet.dart

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ abstract class ElectrumWalletBase
6363
ElectrumWalletBase({
6464
required String password,
6565
required WalletInfo walletInfo,
66+
required DerivationInfo derivationInfo,
6667
required Box<UnspentCoinsInfo> unspentCoinsInfo,
6768
required this.network,
6869
required this.encryptionFileUtils,
@@ -75,9 +76,8 @@ abstract class ElectrumWalletBase
7576
ElectrumBalance? initialBalance,
7677
CryptoCurrency? currency,
7778
bool? alwaysScan,
78-
})
79-
: accountHD = getAccountHDWallet(currency, network, seedBytes, xpub,
80-
walletInfo.derivationInfo, walletInfo.hardwareWalletType),
79+
}) : accountHD =
80+
getAccountHDWallet(currency, network, seedBytes, xpub, derivationInfo, walletInfo.hardwareWalletType),
8181
syncStatus = NotConnectedSyncStatus(),
8282
_password = password,
8383
_feeRates = <int>[],
@@ -100,9 +100,10 @@ abstract class ElectrumWalletBase
100100
this.unspentCoinsInfo = unspentCoinsInfo,
101101
this.isTestnet = !network.isMainnet,
102102
this._mnemonic = mnemonic,
103-
super(walletInfo) {
103+
super(walletInfo, derivationInfo) {
104104
this.electrumClient = electrumClient ?? electrum.ElectrumClient();
105105
this.walletInfo = walletInfo;
106+
this.derivationInfo = derivationInfo;
106107
transactionHistory = ElectrumTransactionHistory(
107108
walletInfo: walletInfo,
108109
password: password,
@@ -771,8 +772,9 @@ abstract class ElectrumWalletBase
771772
pubKeyHex = hd.childKey(Bip32KeyIndex(utx.bitcoinAddressRecord.index)).publicKey.toHex();
772773
}
773774

775+
774776
final derivationPath =
775-
"${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? electrum_path)}"
777+
"${_hardenedDerivationPath(derivationInfo.derivationPath ?? electrum_path)}"
776778
"/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}"
777779
"/${utx.bitcoinAddressRecord.index}";
778780
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
@@ -981,7 +983,7 @@ abstract class ElectrumWalletBase
981983

982984
// Get Derivation path for change Address since it is needed in Litecoin and BitcoinCash hardware Wallets
983985
final changeDerivationPath =
984-
"${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? "m/0'")}"
986+
"${_hardenedDerivationPath(derivationInfo.derivationPath ?? "m/0'")}"
985987
"/${changeAddress.isHidden ? "1" : "0"}"
986988
"/${changeAddress.index}";
987989
utxoDetails.publicKeys[address.pubKeyHash()] =
@@ -1447,8 +1449,8 @@ abstract class ElectrumWalletBase
14471449
? SegwitAddresType.p2wpkh.toString()
14481450
: walletInfo.addressPageType.toString(),
14491451
'balance': balance[currency]?.toJSON(),
1450-
'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index,
1451-
'derivationPath': walletInfo.derivationInfo?.derivationPath,
1452+
'derivationTypeIndex': derivationInfo.derivationType?.index,
1453+
'derivationPath': derivationInfo.derivationPath,
14521454
'silent_addresses': walletAddresses.silentAddresses.map((addr) => addr.toJSON()).toList(),
14531455
'silent_address_index': walletAddresses.currentSilentAddressIndex.toString(),
14541456
'mweb_addresses': walletAddresses.mwebAddresses.map((addr) => addr.toJSON()).toList(),

0 commit comments

Comments
 (0)