Files
hash-wallet/lib/view_model/wallet_restore_view_model.dart
T
jwinterm dd449f2594 Merge upstream Cake Wallet v6.5.0
Catches up from the May 12 fork point (v6.1.2+23) through v6.5.0: 535
upstream commits, including the Monero silent-open fix, Monero on Trezor,
Ledger/Trezor BLE fixes, the new seed and history screens, quick Bitcoin
sync, git-pinned dependencies (pubspec_overrides.yaml), frozen Hive
adapters (*.part.dart), monero_c v0.18.4.6-RC2 and Flutter 3.41.9.

Merged with both sides normalized first (import rename, 100-column
format), which took the conflict count from 614 paths to 322. The
procedure is now scripts/upstream_sync.sh.

Kept from Hash Bags:
- WalletType enum order and Hive IDs. SQLite stores WalletType.index and
  our order differs from upstream's; taking theirs would reread saved
  wallets as other chains. Our frozen adapter keeps the shipped IDs.
- The 1.0.2 legacy PIN and wallet-password decode and self-heal.
- Removed chains (Solana, Tron, Zano, Zcash, Decred, Haven) and the new
  Robinhood chain stay out; Cake Pay and non-Trocador swaps stay out.
- Default nodes (node.wownero.org, sethforprivacy, Blockstream, bysh.me),
  converted to upstream's isDefault node-list key; Wownero is back in the
  node reset list.
- Privacy: address resolvers limited to domain-anchored sources again;
  prices.neroswap.com for fiat; upstream's charts tab, which reads
  prices.cakewallet.com, sits behind FeatureFlag.isChartsEnabled = false.
- Lightning stays behind FeatureFlag.isLightningEnabled, including
  upstream's new post-seed Lightning username step.
- Our icon pipeline, branding and bundle identifiers.

Twelve new upstream widget tests are skipped: test and code are unchanged
from v6.5.0 apart from renames (not rerun on a pristine upstream checkout;
upstream's top_bar_test does not compile against its own TopBar).
flutter analyze lib: 0 errors; flutter test: 345 passed, 12 skipped;
flutter build bundle compiles. Built with Flutter 3.41.9.
2026-10-24 23:49:29 -04:00

300 lines
10 KiB
Dart

import 'package:hash_wallet/bitcoin/bitcoin.dart';
import 'package:hash_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:hash_wallet/core/generate_wallet_password.dart';
import 'package:hash_wallet/core/wallet_creation_service.dart';
import 'package:hash_wallet/di.dart';
import 'package:hash_wallet/dogecoin/dogecoin.dart';
import 'package:hash_wallet/evm/evm.dart';
import 'package:hash_wallet/monero/monero.dart';
import 'package:hash_wallet/nano/nano.dart';
import 'package:hash_wallet/reactions/wallet_connect.dart';
import 'package:hash_wallet/store/app_store.dart';
import 'package:hash_wallet/utils/feature_flag.dart';
import 'package:hash_wallet/view_model/restore/restore_mode.dart';
import 'package:hash_wallet/view_model/restore/restore_wallet.dart';
import 'package:hash_wallet/view_model/seed_settings_view_model.dart';
import 'package:hash_wallet/view_model/wallet_creation_vm.dart';
import 'package:hash_wallet/wownero/wownero.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
part 'wallet_restore_view_model.g.dart';
class WalletRestoreViewModel = WalletRestoreViewModelBase with _$WalletRestoreViewModel;
abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
SeedSettingsViewModel seedSettingsViewModel,
{required WalletType type, this.restoredWallet, this.hardwareWalletType})
: isButtonEnabled = restoredWallet != null,
hasPassphrase = false,
mode = restoredWallet?.restoreMode ?? WalletRestoreMode.seed,
super(appStore, walletCreationService, seedSettingsViewModel,
type: type, isRecovery: true) {
switch (type) {
case WalletType.monero:
availableModes = WalletRestoreMode.values;
break;
case WalletType.nano:
case WalletType.banano:
case WalletType.wownero:
case WalletType.ethereum:
case WalletType.polygon:
case WalletType.base:
case WalletType.arbitrum:
case WalletType.bsc:
case WalletType.bitcoin:
case WalletType.litecoin:
availableModes = [WalletRestoreMode.seed, WalletRestoreMode.keys];
break;
case WalletType.bitcoinCash:
case WalletType.dogecoin:
availableModes = [WalletRestoreMode.seed];
break;
case WalletType.none:
availableModes = [];
}
walletCreationService.changeWalletType(type: type);
if (restoredWallet != null) {
if (restoredWallet!.restoreMode == WalletRestoreMode.seed) {
seedSettingsViewModel.setPassphrase(restoredWallet!.passphrase);
}
}
}
static const moneroSeedMnemonicLength = 25;
late List<WalletRestoreMode> availableModes;
late final bool hasSeedLanguageSelector = [WalletType.monero, WalletType.wownero].contains(type);
late final bool hasBlockchainHeightSelector =
[WalletType.monero, WalletType.wownero].contains(type);
late final bool hasRestoreFromPrivateKey = [
WalletType.ethereum,
WalletType.polygon,
WalletType.base,
WalletType.arbitrum,
WalletType.bsc,
WalletType.nano,
WalletType.banano,
].contains(type);
late final bool onlyViewKeyRestore =
[if (FeatureFlag.hasBitcoinViewOnly) WalletType.bitcoin].contains(type);
final RestoredWallet? restoredWallet;
final HardwareWalletType? hardwareWalletType;
@observable
WalletRestoreMode mode;
@computed
bool get passphraseAvailable => mode == WalletRestoreMode.seed;
@observable
bool hasPassphrase;
@observable
bool isButtonEnabled;
@override
WalletCredentials getCredentials(dynamic options) {
final password = walletPassword ?? generateWalletPassword();
String? passphrase = options['passphrase'] as String?;
final height = options['height'] as int? ?? 0;
name = options['name'] as String;
DerivationInfo? derivationInfo = options["derivationInfo"] as DerivationInfo?;
if (mode == WalletRestoreMode.seed) {
final seed = options['seed'] as String;
switch (type) {
case WalletType.monero:
return monero!.createMoneroRestoreWalletFromSeedCredentials(
name: name,
height: height,
mnemonic: seed,
password: password,
passphrase: passphrase ?? '');
case WalletType.bitcoin:
case WalletType.litecoin:
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
passphrase: passphrase,
derivationType: derivationInfo!.derivationType!,
derivationPath: derivationInfo.derivationPath!,
);
case WalletType.bitcoinCash:
return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
passphrase: passphrase,
);
case WalletType.dogecoin:
return dogecoin!.createDogeCoinRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
passphrase: passphrase,
);
case WalletType.nano:
case WalletType.banano:
return nano!.createNanoRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
derivationType: derivationInfo!.derivationType!,
passphrase: passphrase,
);
case WalletType.ethereum:
case WalletType.polygon:
case WalletType.base:
case WalletType.arbitrum:
case WalletType.bsc:
return evm!.createEVMRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
passphrase: passphrase,
);
case WalletType.wownero:
return wownero!.createWowneroRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
passphrase: passphrase ?? '',
height: height,
);
case WalletType.none:
break;
}
}
if (mode == WalletRestoreMode.keys) {
final viewKey = options['viewKey'] as String?;
final spendKey = options['spendKey'] as String?;
final scanSecret = options['scanSecret'] as String?;
final spendPubkey = options['spendPubkey'] as String?;
final address = options['address'] as String?;
switch (type) {
case WalletType.bitcoin:
return bitcoin!.createBitcoinWalletFromKeys(
name: name,
password: password,
xpub: viewKey!,
hardwareWalletType: hardwareWalletType,
);
case WalletType.litecoin:
return bitcoin!.createLitecoinWalletFromKeys(
name: name,
password: password,
xpub: viewKey!,
scanSecret: scanSecret!,
spendPubkey: spendPubkey!,
hardwareWalletType: hardwareWalletType,
);
case WalletType.monero:
return monero!.createMoneroRestoreWalletFromKeysCredentials(
name: name,
height: height,
spendKey: spendKey!,
viewKey: viewKey!,
address: address!,
password: password,
language: 'English',
hardwareWalletType: hardwareWalletType);
case WalletType.nano:
return nano!.createNanoRestoreWalletFromKeysCredentials(
name: name,
password: password,
seedKey: options['private_key'] as String,
derivationType: derivationInfo!.derivationType!,
);
case WalletType.ethereum:
case WalletType.polygon:
case WalletType.base:
case WalletType.arbitrum:
case WalletType.bsc:
return evm!.createEVMRestoreWalletFromPrivateKey(
name: name,
password: password,
privateKey: options['private_key'] as String,
);
case WalletType.wownero:
return wownero!.createWowneroRestoreWalletFromKeysCredentials(
name: name,
height: height,
spendKey: spendKey!,
viewKey: viewKey!,
address: address!,
password: password,
language: 'English',
);
default:
break;
}
}
throw Exception('Unexpected type: ${type.toString()}');
}
Future<List<DerivationInfo>> getDerivationInfo(dynamic credentials) async {
var list = <DerivationInfo>[];
var walletType = credentials["walletType"] as WalletType;
var appStore = getIt.get<AppStore>();
int? chainId;
if (isEVMCompatibleChain(walletType)) {
if (appStore.wallet != null) {
chainId = evm!.getSelectedChainId(appStore.wallet!);
}
chainId ??= evm!.getChainIdByWalletType(walletType);
}
var node = appStore.settingsStore.getCurrentNode(walletType, chainId: chainId);
switch (walletType) {
case WalletType.bitcoin:
case WalletType.litecoin:
String? mnemonic = credentials['seed'] as String?;
String? passphrase = credentials['passphrase'] as String?;
if (mnemonic == null) break;
return bitcoin!.getDerivationsFromMnemonic(
mnemonic: mnemonic,
node: node,
passphrase: passphrase,
);
case WalletType.nano:
String? mnemonic = credentials['seed'] as String?;
String? seedKey = credentials['private_key'] as String?;
return nanoUtil!.getDerivationsFromMnemonic(
mnemonic: mnemonic,
seedKey: seedKey,
node: node,
);
default:
break;
}
return list;
}
@override
Future<WalletBase> process(WalletCredentials credentials) async {
if (mode == WalletRestoreMode.keys) {
return walletCreationService.restoreFromKeys(credentials, isTestnet: useTestnet);
}
return walletCreationService.restoreFromSeed(credentials, isTestnet: useTestnet);
}
}