mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
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
This commit is contained in:
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
|
||||
walletInfo: walletInfo,
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
derivationInfo: DerivationInfo(
|
||||
derivationType: derivationType,
|
||||
derivationPath: derivationPath,
|
||||
),
|
||||
);
|
||||
|
||||
final String? mnemonic;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
walletInfo.setAddresses(addressesMap);
|
||||
walletInfo.setAddressInfos(addressInfos);
|
||||
walletInfo.setUsedAddresses(usedAddresses.toList());
|
||||
walletInfo.setHiddenAddresses(hiddenAddresses.toList());
|
||||
walletInfo.setManualAddresses(manualAddresses.toList());
|
||||
|
||||
if (walletInfo.isInBox) {
|
||||
await walletInfo.save();
|
||||
}
|
||||
await walletInfo.save();
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+456
-94
@@ -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';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/wallet_info_legacy.dart' as wiLegacy;
|
||||
|
||||
part 'wallet_info.g.dart';
|
||||
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;
|
||||
|
||||
static String get tableName => 'walletInfoDerivationInfo';
|
||||
static String get selfIdColumn => "${tableName}Id";
|
||||
|
||||
@HiveField(0, defaultValue: '')
|
||||
String address;
|
||||
|
||||
@HiveField(1, defaultValue: '')
|
||||
String balance;
|
||||
|
||||
@HiveField(2, defaultValue: 0)
|
||||
int transactionsCount;
|
||||
|
||||
@HiveField(3)
|
||||
DerivationType? derivationType;
|
||||
|
||||
@HiveField(4)
|
||||
String? derivationPath;
|
||||
String? scriptType;
|
||||
String? description;
|
||||
|
||||
@HiveField(5)
|
||||
final String? scriptType;
|
||||
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(6)
|
||||
final String? description;
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
selfIdColumn: id,
|
||||
"address": address,
|
||||
"balance": balance,
|
||||
"transactionsCount": transactionsCount,
|
||||
"derivationType": derivationType?.index,
|
||||
"derivationPath": derivationPath,
|
||||
"scriptType": scriptType,
|
||||
"description": 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";
|
||||
|
||||
int internalId;
|
||||
|
||||
@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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addAddress(String address, WalletInfoAddressType type) async {
|
||||
await WalletInfoAddress.insert(internalId, type, address);
|
||||
}
|
||||
|
||||
@HiveField(18)
|
||||
String? addressPageType;
|
||||
|
||||
@HiveField(19)
|
||||
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();
|
||||
|
||||
@@ -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)');
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -14,6 +14,7 @@ class NanoNewWalletCredentials extends WalletCredentials {
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
passphrase: passphrase,
|
||||
derivationInfo: DerivationInfo(derivationType: derivationType),
|
||||
);
|
||||
|
||||
final String? mnemonic;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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((_) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+24
-43
@@ -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>()));
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1032,7 +1032,7 @@ class YoCupertinoLocalizations extends GlobalCupertinoLocalizations {
|
||||
@override
|
||||
// TODO: implement backButtonLabel
|
||||
String get backButtonLabel => "backButtonLabel";
|
||||
|
||||
|
||||
@override
|
||||
// TODO: implement cancelButtonLabel
|
||||
String get cancelButtonLabel => "cancelButtonLabel";
|
||||
|
||||
+8
-23
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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: (_) {
|
||||
|
||||
@@ -258,7 +258,7 @@ class WalletRestorePage extends BasePage {
|
||||
return;
|
||||
}
|
||||
|
||||
if (walletRestoreViewModel.nameExists(name)) {
|
||||
if (await walletRestoreViewModel.nameExists(name)) {
|
||||
showNameExistsAlert(formContext!);
|
||||
_formProcessing = false;
|
||||
return;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 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 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -243,9 +243,7 @@ abstract class YatStoreBase with Store {
|
||||
|
||||
walletInfo!.yatEid = emoji;
|
||||
|
||||
if (walletInfo!.isInBox) {
|
||||
walletInfo!.save();
|
||||
}
|
||||
walletInfo!.save();
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -78,13 +84,14 @@ abstract class ContactListViewModelBase with Store {
|
||||
walletTypeToCryptoCurrency(info.type),
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_subscription = contactSource.bindToListWithTransform(
|
||||
contacts, (Contact contact) => ContactRecord(contactSource, contact),
|
||||
initialFire: true);
|
||||
|
||||
setOrderType(settingsStore.contactListOrder);
|
||||
walletContacts = walletContacts.toList(); // rebuild
|
||||
}
|
||||
|
||||
String _createName(String walletName, String label, {int? key = null}) {
|
||||
@@ -97,9 +104,9 @@ abstract class ContactListViewModelBase with Store {
|
||||
|
||||
final bool isAutoGenerateEnabled;
|
||||
final Box<Contact> contactSource;
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
final ObservableList<ContactRecord> contacts;
|
||||
final List<WalletContact> walletContacts;
|
||||
@observable
|
||||
List<WalletContact> walletContacts = [];
|
||||
final CryptoCurrency? _currency;
|
||||
StreamSubscription<BoxEvent>? _subscription;
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
@@ -1098,8 +1098,8 @@ abstract class DashboardViewModelBase with Store {
|
||||
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
|
||||
|
||||
Future<List<String>> checkForHavenWallets() async {
|
||||
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
return walletInfoSource.values
|
||||
final walletInfos = await WalletInfo.getAll();
|
||||
return walletInfos
|
||||
.where((element) => element.type == WalletType.haven)
|
||||
.map((e) => e.name)
|
||||
.toList();
|
||||
@@ -1112,10 +1112,9 @@ abstract class DashboardViewModelBase with Store {
|
||||
.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
|
||||
final vulnerableSeeds = vulnerableSeedsString.split("\n");
|
||||
|
||||
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
|
||||
List<String> affectedWallets = [];
|
||||
for (var walletInfo in walletInfoSource.values) {
|
||||
final walletInfos = await WalletInfo.getAll();
|
||||
for (var walletInfo in walletInfos) {
|
||||
if (walletInfo.type == WalletType.bitcoin) {
|
||||
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
|
||||
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||
|
||||
@@ -44,6 +44,7 @@ import 'package:cake_wallet/utils/token_utilities.dart';
|
||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/fees_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_model.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
@@ -82,7 +83,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
this.contactListViewModel,
|
||||
this.unspentCoinsListViewModel,
|
||||
this.feesViewModel,
|
||||
this.walletInfoSource,
|
||||
this.fiatConversionStore,
|
||||
) : _cryptoNumberFormat = NumberFormat(),
|
||||
isSendAllEnabled = false,
|
||||
@@ -369,8 +369,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
final FeesViewModel feesViewModel;
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
|
||||
@observable
|
||||
double bestRate = 0.0;
|
||||
|
||||
@@ -1096,7 +1094,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
@action
|
||||
Future<void> _injectUserEthTokensIntoCurrencyLists() async {
|
||||
final userTokens = await TokenUtilities.loadAllUniqueEvmTokens(walletInfoSource);
|
||||
final userTokens = await TokenUtilities.loadAllUniqueEvmTokens();
|
||||
|
||||
final toAddReceive = <CryptoCurrency>[];
|
||||
final toAddDeposit = <CryptoCurrency>[];
|
||||
@@ -1134,7 +1132,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
@action
|
||||
Future<void> _injectUserSplTokensIntoCurrencyLists() async {
|
||||
final userTokens = await TokenUtilities.loadAllUniqueSolTokens(walletInfoSource);
|
||||
final userTokens = await TokenUtilities.loadAllUniqueSolTokens();
|
||||
|
||||
final toAddReceive = <CryptoCurrency>[];
|
||||
final toAddDeposit = <CryptoCurrency>[];
|
||||
@@ -1162,7 +1160,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
@action
|
||||
Future<void> _injectUserTronTokensIntoCurrencyLists() async {
|
||||
final userTokens = await TokenUtilities.loadAllUniqueTronTokens(walletInfoSource);
|
||||
final userTokens = await TokenUtilities.loadAllUniqueTronTokens();
|
||||
|
||||
final toAddReceive = <CryptoCurrency>[];
|
||||
final toAddDeposit = <CryptoCurrency>[];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user