Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pr_test_build_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,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: |
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 16 additions & 8 deletions cw_bitcoin/lib/bitcoin_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,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,
Expand All @@ -68,6 +69,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
xpub: xpub,
password: password,
walletInfo: walletInfo,
derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
network: networkParam == null
? BitcoinNetwork.mainnet
Expand Down Expand Up @@ -132,7 +134,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,
Expand All @@ -151,6 +155,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
passphrase: passphrase ?? "",
password: password,
walletInfo: walletInfo,
derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialSilentAddresses: initialSilentAddresses,
Expand Down Expand Up @@ -211,20 +216,20 @@ 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;

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 ?? "");
Expand All @@ -245,6 +250,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
password: password,
passphrase: passphrase,
walletInfo: walletInfo,
derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp?.addresses,
initialSilentAddresses: snp?.silentAddresses,
Expand All @@ -264,10 +270,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
BitcoinLedgerApp? _bitcoinLedgerApp;

@override
void setLedgerConnection(LedgerConnection connection) {
Future<void> setLedgerConnection(LedgerConnection connection) async {
_ledgerConnection = connection;
final derivationInfo = await walletInfo.getDerivationInfo();
_bitcoinLedgerApp = BitcoinLedgerApp(_ledgerConnection!,
derivationPath: walletInfo.derivationInfo!.derivationPath!);
derivationPath: derivationInfo.derivationPath!);
}

@override
Expand Down Expand Up @@ -491,7 +498,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;

Expand Down
4 changes: 4 additions & 0 deletions cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
walletInfo: walletInfo,
password: password,
passphrase: passphrase,
derivationInfo: DerivationInfo(
derivationType: derivationType,
derivationPath: derivationPath,
),
);

final String? mnemonic;
Expand Down
41 changes: 29 additions & 12 deletions cw_bitcoin/lib/bitcoin_wallet_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,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;
Expand All @@ -39,7 +38,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;

Expand All @@ -50,6 +55,7 @@ class BitcoinWalletService extends WalletService<
mnemonic = await generateElectrumMnemonic();
break;
}
await derivationInfo.save();

final wallet = await BitcoinWalletBase.create(
mnemonic: mnemonic,
Expand All @@ -74,8 +80,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,
Expand Down Expand Up @@ -106,9 +114,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();
Expand All @@ -122,8 +132,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,
Expand All @@ -140,20 +152,24 @@ class BitcoinWalletService extends WalletService<
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;

await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
await newWalletInfo.save();
}

@override
Future<BitcoinWallet> restoreFromHardwareWallet(BitcoinRestoreWalletFromHardware credentials,
{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;
await derivationInfo.save();
credentials.walletInfo!.save();
final wallet = await BitcoinWallet(
password: credentials.password!,
xpub: credentials.hwAccountData.xpub,
walletInfo: credentials.walletInfo!,
derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
networkParam: network,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
Expand All @@ -174,6 +190,7 @@ class BitcoinWalletService extends WalletService<
password: credentials.password!,
xpub: credentials.xpub,
walletInfo: credentials.walletInfo!,
derivationInfo: await credentials.walletInfo!.getDerivationInfo(),
unspentCoinsInfo: unspentCoinsInfoSource,
networkParam: network,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
Expand Down
17 changes: 10 additions & 7 deletions cw_bitcoin/lib/electrum_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -76,7 +77,7 @@ abstract class ElectrumWalletBase
CryptoCurrency? currency,
bool? alwaysScan,
}) : accountHD =
getAccountHDWallet(currency, network, seedBytes, xpub, walletInfo.derivationInfo),
getAccountHDWallet(currency, network, seedBytes, xpub, derivationInfo),
syncStatus = NotConnectedSyncStatus(),
_password = password,
_feeRates = <int>[],
Expand All @@ -99,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,
Expand Down Expand Up @@ -759,8 +761,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);
Expand Down Expand Up @@ -969,7 +972,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()] =
Expand Down Expand Up @@ -1408,7 +1411,7 @@ abstract class ElectrumWalletBase
}
}

void setLedgerConnection(ledger.LedgerConnection connection) => throw UnimplementedError();
Future<void> setLedgerConnection(ledger.LedgerConnection connection) => throw UnimplementedError();

Future<BtcTransaction> buildHardwareWalletTransaction({
required List<BitcoinBaseOutput> outputs,
Expand All @@ -1435,8 +1438,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(),
Expand Down
21 changes: 13 additions & 8 deletions cw_bitcoin/lib/litecoin_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -166,6 +168,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,
Expand All @@ -177,7 +180,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,
Expand All @@ -193,6 +196,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
derivationInfo: derivationInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialMwebAddresses: initialMwebAddresses,
Expand Down Expand Up @@ -243,18 +247,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,
Expand All @@ -267,12 +270,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,
Expand Down Expand Up @@ -1372,10 +1377,10 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
LitecoinLedgerApp? _litecoinLedgerApp;

@override
void setLedgerConnection(LedgerConnection connection) {
Future<void> setLedgerConnection(LedgerConnection connection) async {
_ledgerConnection = connection;
_litecoinLedgerApp = LitecoinLedgerApp(_ledgerConnection!,
derivationPath: walletInfo.derivationInfo!.derivationPath!);
derivationPath: derivationInfo.derivationPath!);
}

@override
Expand Down
Loading
Loading