mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
Merge pull request #1041 from cypherstack/frost-init-fix
Various fixes and tweaks
This commit is contained in:
commit
a74c565f9a
9 changed files with 314 additions and 252 deletions
|
@ -26,18 +26,20 @@ import '../../../services/transaction_notification_tracker.dart';
|
||||||
import '../../../themes/stack_colors.dart';
|
import '../../../themes/stack_colors.dart';
|
||||||
import '../../../utilities/assets.dart';
|
import '../../../utilities/assets.dart';
|
||||||
import '../../../utilities/logger.dart';
|
import '../../../utilities/logger.dart';
|
||||||
|
import '../../../utilities/show_loading.dart';
|
||||||
import '../../../utilities/text_styles.dart';
|
import '../../../utilities/text_styles.dart';
|
||||||
import '../../../utilities/util.dart';
|
import '../../../utilities/util.dart';
|
||||||
import '../../../wallets/crypto_currency/crypto_currency.dart';
|
import '../../../wallets/crypto_currency/crypto_currency.dart';
|
||||||
import '../../../wallets/isar/models/wallet_info.dart';
|
import '../../../wallets/isar/models/wallet_info.dart';
|
||||||
|
import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
|
||||||
import '../../../wallets/wallet/wallet.dart';
|
import '../../../wallets/wallet/wallet.dart';
|
||||||
import '../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
import '../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
||||||
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import '../../../widgets/desktop/desktop_app_bar.dart';
|
import '../../../widgets/desktop/desktop_app_bar.dart';
|
||||||
import '../../../widgets/desktop/desktop_scaffold.dart';
|
import '../../../widgets/desktop/desktop_scaffold.dart';
|
||||||
import '../../../widgets/loading_indicator.dart';
|
|
||||||
import '../../../widgets/rounded_container.dart';
|
import '../../../widgets/rounded_container.dart';
|
||||||
import '../../../widgets/rounded_white_container.dart';
|
import '../../../widgets/rounded_white_container.dart';
|
||||||
|
import '../../../widgets/stack_dialog.dart';
|
||||||
import '../new_wallet_options/new_wallet_options_view.dart';
|
import '../new_wallet_options/new_wallet_options_view.dart';
|
||||||
import '../new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
|
import '../new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
|
||||||
import 'recovery_phrase_explanation_dialog.dart';
|
import 'recovery_phrase_explanation_dialog.dart';
|
||||||
|
@ -65,6 +67,221 @@ class _NewWalletRecoveryPhraseWarningViewState
|
||||||
late final String walletName;
|
late final String walletName;
|
||||||
late final bool isDesktop;
|
late final bool isDesktop;
|
||||||
|
|
||||||
|
Future<void> _initNewWallet() async {
|
||||||
|
Exception? ex;
|
||||||
|
final result = await showLoading(
|
||||||
|
whileFuture: _initNewFuture(),
|
||||||
|
context: context,
|
||||||
|
message: "Generating...",
|
||||||
|
onException: (e) => ex = e,
|
||||||
|
);
|
||||||
|
|
||||||
|
// on failure show error message
|
||||||
|
if (result == null) {
|
||||||
|
if (mounted) {
|
||||||
|
await showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => StackOkDialog(
|
||||||
|
title: "Create Wallet Error",
|
||||||
|
message: ex?.toString() ?? "Unknown error",
|
||||||
|
maxWidth: 600,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (mounted) {
|
||||||
|
final nav = Navigator.of(context);
|
||||||
|
unawaited(
|
||||||
|
nav.pushNamed(
|
||||||
|
NewWalletRecoveryPhraseView.routeName,
|
||||||
|
arguments: Tuple2(
|
||||||
|
result.$1,
|
||||||
|
result.$2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<(Wallet, List<String>)> _initNewFuture() async {
|
||||||
|
try {
|
||||||
|
String? otherDataJsonString;
|
||||||
|
if (widget.coin is Tezos) {
|
||||||
|
otherDataJsonString = jsonEncode({
|
||||||
|
WalletInfoKeys.tezosDerivationPath:
|
||||||
|
Tezos.standardDerivationPath.value,
|
||||||
|
});
|
||||||
|
// }//todo: probably not needed (broken anyways)
|
||||||
|
// else if (widget.coin is Epiccash) {
|
||||||
|
// final int secondsSinceEpoch =
|
||||||
|
// DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||||
|
// const int epicCashFirstBlock = 1565370278;
|
||||||
|
// const double overestimateSecondsPerBlock = 61;
|
||||||
|
// int chosenSeconds = secondsSinceEpoch - epicCashFirstBlock;
|
||||||
|
// int approximateHeight = chosenSeconds ~/ overestimateSecondsPerBlock;
|
||||||
|
// /
|
||||||
|
// // debugPrint(
|
||||||
|
// // "approximate height: $approximateHeight chosen_seconds: $chosenSeconds");
|
||||||
|
// height = approximateHeight;
|
||||||
|
// if (height < 0) {
|
||||||
|
// height = 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// otherDataJsonString = jsonEncode(
|
||||||
|
// {
|
||||||
|
// WalletInfoKeys.epiccashData: jsonEncode(
|
||||||
|
// ExtraEpiccashWalletInfo(
|
||||||
|
// receivingIndex: 0,
|
||||||
|
// changeIndex: 0,
|
||||||
|
// slatesToAddresses: {},
|
||||||
|
// slatesToCommits: {},
|
||||||
|
// lastScannedBlock: epicCashFirstBlock,
|
||||||
|
// restoreHeight: height,
|
||||||
|
// creationHeight: height,
|
||||||
|
// ).toMap(),
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
} else if (widget.coin is Firo) {
|
||||||
|
otherDataJsonString = jsonEncode(
|
||||||
|
{
|
||||||
|
WalletInfoKeys.lelantusCoinIsarRescanRequired: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final info = WalletInfo.createNew(
|
||||||
|
coin: widget.coin,
|
||||||
|
name: widget.walletName,
|
||||||
|
otherDataJsonString: otherDataJsonString,
|
||||||
|
);
|
||||||
|
|
||||||
|
var node = ref
|
||||||
|
.read(
|
||||||
|
nodeServiceChangeNotifierProvider,
|
||||||
|
)
|
||||||
|
.getPrimaryNodeFor(
|
||||||
|
currency: coin,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (node == null) {
|
||||||
|
node = coin.defaultNode;
|
||||||
|
await ref
|
||||||
|
.read(
|
||||||
|
nodeServiceChangeNotifierProvider,
|
||||||
|
)
|
||||||
|
.setPrimaryNodeFor(
|
||||||
|
coin: coin,
|
||||||
|
node: node,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final txTracker = TransactionNotificationTracker(
|
||||||
|
walletId: info.walletId,
|
||||||
|
);
|
||||||
|
|
||||||
|
String? mnemonicPassphrase;
|
||||||
|
String? mnemonic;
|
||||||
|
String? privateKey;
|
||||||
|
|
||||||
|
// set some sane default
|
||||||
|
int wordCount = info.coin.defaultSeedPhraseLength;
|
||||||
|
|
||||||
|
// TODO: Refactor these to generate each coin in their respective classes
|
||||||
|
// This code should not be in a random view page file
|
||||||
|
if (coin is Monero || coin is Wownero) {
|
||||||
|
// currently a special case due to the
|
||||||
|
// xmr/wow libraries handling their
|
||||||
|
// own mnemonic generation
|
||||||
|
wordCount = ref.read(pNewWalletOptions)?.mnemonicWordsCount ??
|
||||||
|
info.coin.defaultSeedPhraseLength;
|
||||||
|
} else if (wordCount > 0) {
|
||||||
|
if (ref
|
||||||
|
.read(
|
||||||
|
pNewWalletOptions.state,
|
||||||
|
)
|
||||||
|
.state !=
|
||||||
|
null) {
|
||||||
|
if (coin.hasMnemonicPassphraseSupport) {
|
||||||
|
mnemonicPassphrase = ref
|
||||||
|
.read(
|
||||||
|
pNewWalletOptions.state,
|
||||||
|
)
|
||||||
|
.state!
|
||||||
|
.mnemonicPassphrase;
|
||||||
|
} else {
|
||||||
|
// this may not be epiccash specific?
|
||||||
|
if (coin is Epiccash) {
|
||||||
|
mnemonicPassphrase = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wordCount = ref
|
||||||
|
.read(
|
||||||
|
pNewWalletOptions.state,
|
||||||
|
)
|
||||||
|
.state!
|
||||||
|
.mnemonicWordsCount;
|
||||||
|
} else {
|
||||||
|
mnemonicPassphrase = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wordCount < 12 || 24 < wordCount || wordCount % 3 != 0) {
|
||||||
|
throw Exception(
|
||||||
|
"Invalid word count",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final strength = (wordCount ~/ 3) * 32;
|
||||||
|
|
||||||
|
mnemonic = bip39.generateMnemonic(
|
||||||
|
strength: strength,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final wallet = await Wallet.create(
|
||||||
|
walletInfo: info,
|
||||||
|
mainDB: ref.read(mainDBProvider),
|
||||||
|
secureStorageInterface: ref.read(secureStoreProvider),
|
||||||
|
nodeService: ref.read(
|
||||||
|
nodeServiceChangeNotifierProvider,
|
||||||
|
),
|
||||||
|
prefs: ref.read(
|
||||||
|
prefsChangeNotifierProvider,
|
||||||
|
),
|
||||||
|
mnemonicPassphrase: mnemonicPassphrase,
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
privateKey: privateKey,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (wallet is LibMoneroWallet) {
|
||||||
|
await wallet.init(wordCount: wordCount);
|
||||||
|
} else {
|
||||||
|
await wallet.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// set checkbox back to unchecked to annoy users to agree again :P
|
||||||
|
ref
|
||||||
|
.read(
|
||||||
|
checkBoxStateProvider.state,
|
||||||
|
)
|
||||||
|
.state = false;
|
||||||
|
|
||||||
|
final fetchedMnemonic =
|
||||||
|
await (wallet as MnemonicInterface).getMnemonicAsWords();
|
||||||
|
|
||||||
|
return (wallet, fetchedMnemonic);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$e\n$s",
|
||||||
|
level: LogLevel.Fatal,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
coin = widget.coin;
|
coin = widget.coin;
|
||||||
|
@ -454,222 +671,7 @@ class _NewWalletRecoveryPhraseWarningViewState
|
||||||
onPressed: ref
|
onPressed: ref
|
||||||
.read(checkBoxStateProvider.state)
|
.read(checkBoxStateProvider.state)
|
||||||
.state
|
.state
|
||||||
? () async {
|
? _initNewWallet
|
||||||
try {
|
|
||||||
unawaited(
|
|
||||||
showDialog<dynamic>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
useSafeArea: true,
|
|
||||||
builder: (ctx) {
|
|
||||||
return const Center(
|
|
||||||
child: LoadingIndicator(
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
String? otherDataJsonString;
|
|
||||||
if (widget.coin is Tezos) {
|
|
||||||
otherDataJsonString = jsonEncode({
|
|
||||||
WalletInfoKeys
|
|
||||||
.tezosDerivationPath:
|
|
||||||
Tezos.standardDerivationPath
|
|
||||||
.value,
|
|
||||||
});
|
|
||||||
// }//todo: probably not needed (broken anyways)
|
|
||||||
// else if (widget.coin is Epiccash) {
|
|
||||||
// final int secondsSinceEpoch =
|
|
||||||
// DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
|
||||||
// const int epicCashFirstBlock = 1565370278;
|
|
||||||
// const double overestimateSecondsPerBlock = 61;
|
|
||||||
// int chosenSeconds = secondsSinceEpoch - epicCashFirstBlock;
|
|
||||||
// int approximateHeight = chosenSeconds ~/ overestimateSecondsPerBlock;
|
|
||||||
// /
|
|
||||||
// // debugPrint(
|
|
||||||
// // "approximate height: $approximateHeight chosen_seconds: $chosenSeconds");
|
|
||||||
// height = approximateHeight;
|
|
||||||
// if (height < 0) {
|
|
||||||
// height = 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// otherDataJsonString = jsonEncode(
|
|
||||||
// {
|
|
||||||
// WalletInfoKeys.epiccashData: jsonEncode(
|
|
||||||
// ExtraEpiccashWalletInfo(
|
|
||||||
// receivingIndex: 0,
|
|
||||||
// changeIndex: 0,
|
|
||||||
// slatesToAddresses: {},
|
|
||||||
// slatesToCommits: {},
|
|
||||||
// lastScannedBlock: epicCashFirstBlock,
|
|
||||||
// restoreHeight: height,
|
|
||||||
// creationHeight: height,
|
|
||||||
// ).toMap(),
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
} else if (widget.coin is Firo) {
|
|
||||||
otherDataJsonString = jsonEncode(
|
|
||||||
{
|
|
||||||
WalletInfoKeys
|
|
||||||
.lelantusCoinIsarRescanRequired:
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final info = WalletInfo.createNew(
|
|
||||||
coin: widget.coin,
|
|
||||||
name: widget.walletName,
|
|
||||||
otherDataJsonString:
|
|
||||||
otherDataJsonString,
|
|
||||||
);
|
|
||||||
|
|
||||||
var node = ref
|
|
||||||
.read(
|
|
||||||
nodeServiceChangeNotifierProvider,
|
|
||||||
)
|
|
||||||
.getPrimaryNodeFor(
|
|
||||||
currency: coin,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (node == null) {
|
|
||||||
node = coin.defaultNode;
|
|
||||||
await ref
|
|
||||||
.read(
|
|
||||||
nodeServiceChangeNotifierProvider,
|
|
||||||
)
|
|
||||||
.setPrimaryNodeFor(
|
|
||||||
coin: coin,
|
|
||||||
node: node,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final txTracker =
|
|
||||||
TransactionNotificationTracker(
|
|
||||||
walletId: info.walletId,
|
|
||||||
);
|
|
||||||
|
|
||||||
int? wordCount;
|
|
||||||
String? mnemonicPassphrase;
|
|
||||||
String? mnemonic;
|
|
||||||
String? privateKey;
|
|
||||||
|
|
||||||
wordCount = info
|
|
||||||
.coin.defaultSeedPhraseLength;
|
|
||||||
|
|
||||||
// TODO: Refactor these to generate each coin in their respective classes
|
|
||||||
// This code should not be in a random view page file
|
|
||||||
if (coin is Monero ||
|
|
||||||
coin is Wownero) {
|
|
||||||
// currently a special case due to the
|
|
||||||
// xmr/wow libraries handling their
|
|
||||||
// own mnemonic generation
|
|
||||||
} else if (wordCount > 0) {
|
|
||||||
if (ref
|
|
||||||
.read(
|
|
||||||
pNewWalletOptions.state,
|
|
||||||
)
|
|
||||||
.state !=
|
|
||||||
null) {
|
|
||||||
if (coin
|
|
||||||
.hasMnemonicPassphraseSupport) {
|
|
||||||
mnemonicPassphrase = ref
|
|
||||||
.read(
|
|
||||||
pNewWalletOptions.state,
|
|
||||||
)
|
|
||||||
.state!
|
|
||||||
.mnemonicPassphrase;
|
|
||||||
} else {
|
|
||||||
// this may not be epiccash specific?
|
|
||||||
if (coin is Epiccash) {
|
|
||||||
mnemonicPassphrase = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wordCount = ref
|
|
||||||
.read(
|
|
||||||
pNewWalletOptions.state,
|
|
||||||
)
|
|
||||||
.state!
|
|
||||||
.mnemonicWordsCount;
|
|
||||||
} else {
|
|
||||||
mnemonicPassphrase = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wordCount < 12 ||
|
|
||||||
24 < wordCount ||
|
|
||||||
wordCount % 3 != 0) {
|
|
||||||
throw Exception(
|
|
||||||
"Invalid word count",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final strength =
|
|
||||||
(wordCount ~/ 3) * 32;
|
|
||||||
|
|
||||||
mnemonic = bip39.generateMnemonic(
|
|
||||||
strength: strength,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final wallet = await Wallet.create(
|
|
||||||
walletInfo: info,
|
|
||||||
mainDB: ref.read(mainDBProvider),
|
|
||||||
secureStorageInterface:
|
|
||||||
ref.read(secureStoreProvider),
|
|
||||||
nodeService: ref.read(
|
|
||||||
nodeServiceChangeNotifierProvider,
|
|
||||||
),
|
|
||||||
prefs: ref.read(
|
|
||||||
prefsChangeNotifierProvider,
|
|
||||||
),
|
|
||||||
mnemonicPassphrase:
|
|
||||||
mnemonicPassphrase,
|
|
||||||
mnemonic: mnemonic,
|
|
||||||
privateKey: privateKey,
|
|
||||||
);
|
|
||||||
|
|
||||||
await wallet.init();
|
|
||||||
|
|
||||||
// pop progress dialog
|
|
||||||
if (context.mounted) {
|
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
// set checkbox back to unchecked to annoy users to agree again :P
|
|
||||||
ref
|
|
||||||
.read(
|
|
||||||
checkBoxStateProvider.state,
|
|
||||||
)
|
|
||||||
.state = false;
|
|
||||||
|
|
||||||
if (context.mounted) {
|
|
||||||
final nav = Navigator.of(context);
|
|
||||||
unawaited(
|
|
||||||
nav.pushNamed(
|
|
||||||
NewWalletRecoveryPhraseView
|
|
||||||
.routeName,
|
|
||||||
arguments: Tuple2(
|
|
||||||
wallet,
|
|
||||||
await (wallet
|
|
||||||
as MnemonicInterface)
|
|
||||||
.getMnemonicAsWords(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e, s) {
|
|
||||||
Logging.instance.log(
|
|
||||||
"$e\n$s",
|
|
||||||
level: LogLevel.Fatal,
|
|
||||||
);
|
|
||||||
// TODO: handle gracefully
|
|
||||||
// any network/socket exception here will break new wallet creation
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: null,
|
: null,
|
||||||
style: ref
|
style: ref
|
||||||
.read(checkBoxStateProvider.state)
|
.read(checkBoxStateProvider.state)
|
||||||
|
|
|
@ -458,7 +458,7 @@ abstract class SWB {
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
mnemonicPassphrase: mnemonicPassphrase,
|
mnemonicPassphrase: mnemonicPassphrase,
|
||||||
);
|
);
|
||||||
|
Wallet? wallet;
|
||||||
try {
|
try {
|
||||||
String? serializedKeys;
|
String? serializedKeys;
|
||||||
String? multisigConfig;
|
String? multisigConfig;
|
||||||
|
@ -491,7 +491,7 @@ abstract class SWB {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final wallet = await Wallet.create(
|
wallet = await Wallet.create(
|
||||||
walletInfo: info,
|
walletInfo: info,
|
||||||
mainDB: MainDB.instance,
|
mainDB: MainDB.instance,
|
||||||
secureStorageInterface: secureStorageInterface,
|
secureStorageInterface: secureStorageInterface,
|
||||||
|
@ -614,6 +614,8 @@ abstract class SWB {
|
||||||
mnemonicPassphrase: mnemonicPassphrase,
|
mnemonicPassphrase: mnemonicPassphrase,
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
} finally {
|
||||||
|
await wallet?.exit();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,9 +316,10 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
||||||
if (wallet is MnemonicInterface) {
|
if (wallet is MnemonicInterface) {
|
||||||
if (wallet
|
if (wallet
|
||||||
is ViewOnlyOptionInterface &&
|
is ViewOnlyOptionInterface &&
|
||||||
!(wallet
|
(wallet as ViewOnlyOptionInterface)
|
||||||
as ViewOnlyOptionInterface)
|
|
||||||
.isViewOnly) {
|
.isViewOnly) {
|
||||||
|
// TODO: is something needed here?
|
||||||
|
} else {
|
||||||
mnemonic = await wallet
|
mnemonic = await wallet
|
||||||
.getMnemonicAsWords();
|
.getMnemonicAsWords();
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,12 +85,26 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
|
||||||
await mainDB.isar.frostWalletInfo.put(frostWalletInfo);
|
await mainDB.isar.frostWalletInfo.put(frostWalletInfo);
|
||||||
});
|
});
|
||||||
|
|
||||||
final address = await _generateAddress(
|
Address? address;
|
||||||
|
int index = kFrostSecureStartingIndex;
|
||||||
|
while (address == null) {
|
||||||
|
try {
|
||||||
|
address = await _generateAddress(
|
||||||
change: 0,
|
change: 0,
|
||||||
index: kFrostSecureStartingIndex,
|
index: index,
|
||||||
serializedKeys: serializedKeys,
|
serializedKeys: serializedKeys,
|
||||||
secure: true,
|
secure: true,
|
||||||
);
|
);
|
||||||
|
} on FrostdartException catch (e) {
|
||||||
|
if (e.errorCode == 72) {
|
||||||
|
// rust doesn't like the addressDerivationData
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await mainDB.putAddresses([address]);
|
await mainDB.putAddresses([address]);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
|
|
@ -701,7 +701,7 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
isar: mainDB.isar,
|
isar: mainDB.isar,
|
||||||
);
|
);
|
||||||
|
|
||||||
unawaited(_startScans());
|
unawaited(refresh(doScan: true));
|
||||||
} else {
|
} else {
|
||||||
await updateNode();
|
await updateNode();
|
||||||
final String password = generatePassword();
|
final String password = generatePassword();
|
||||||
|
@ -759,9 +759,8 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
epicData.receivingIndex,
|
epicData.receivingIndex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
unawaited(refresh(doScan: false));
|
||||||
});
|
});
|
||||||
|
|
||||||
unawaited(refresh());
|
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Exception rethrown from electrumx_mixin recover(): $e\n$s",
|
"Exception rethrown from electrumx_mixin recover(): $e\n$s",
|
||||||
|
@ -773,7 +772,7 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> refresh() async {
|
Future<void> refresh({bool doScan = true}) async {
|
||||||
// Awaiting this lock could be dangerous.
|
// Awaiting this lock could be dangerous.
|
||||||
// Since refresh is periodic (generally)
|
// Since refresh is periodic (generally)
|
||||||
if (refreshMutex.isLocked) {
|
if (refreshMutex.isLocked) {
|
||||||
|
@ -803,9 +802,11 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
final int curAdd = await _getCurrentIndex();
|
final int curAdd = await _getCurrentIndex();
|
||||||
await _generateAndStoreReceivingAddressForIndex(curAdd);
|
await _generateAndStoreReceivingAddressForIndex(curAdd);
|
||||||
|
|
||||||
|
if (doScan) {
|
||||||
await _startScans();
|
await _startScans();
|
||||||
|
|
||||||
unawaited(_startSync());
|
unawaited(_startSync());
|
||||||
|
}
|
||||||
|
|
||||||
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.0, walletId));
|
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.0, walletId));
|
||||||
await updateChainHeight();
|
await updateChainHeight();
|
||||||
|
@ -1157,6 +1158,7 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> exit() async {
|
Future<void> exit() async {
|
||||||
|
epiccash.LibEpiccash.stopEpicboxListener();
|
||||||
timer?.cancel();
|
timer?.cancel();
|
||||||
timer = null;
|
timer = null;
|
||||||
await super.exit();
|
await super.exit();
|
||||||
|
|
|
@ -75,13 +75,28 @@ class MoneroWallet extends LibMoneroWallet {
|
||||||
Future<lib_monero.Wallet> getCreatedWallet({
|
Future<lib_monero.Wallet> getCreatedWallet({
|
||||||
required String path,
|
required String path,
|
||||||
required String password,
|
required String password,
|
||||||
}) async =>
|
required int wordCount,
|
||||||
await lib_monero.MoneroWallet.create(
|
}) async {
|
||||||
|
final lib_monero.MoneroSeedType type;
|
||||||
|
switch (wordCount) {
|
||||||
|
case 16:
|
||||||
|
type = lib_monero.MoneroSeedType.sixteen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 25:
|
||||||
|
type = lib_monero.MoneroSeedType.twentyFive;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Exception("Invalid mnemonic word count: $wordCount");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await lib_monero.MoneroWallet.create(
|
||||||
path: path,
|
path: path,
|
||||||
password: password,
|
password: password,
|
||||||
seedType: lib_monero.MoneroSeedType
|
seedType: type,
|
||||||
.sixteen, // TODO: check we want to actually use 16 here
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<lib_monero.Wallet> getRestoredWallet({
|
Future<lib_monero.Wallet> getRestoredWallet({
|
||||||
|
|
|
@ -111,14 +111,33 @@ class WowneroWallet extends LibMoneroWallet {
|
||||||
Future<lib_monero.Wallet> getCreatedWallet({
|
Future<lib_monero.Wallet> getCreatedWallet({
|
||||||
required String path,
|
required String path,
|
||||||
required String password,
|
required String password,
|
||||||
}) async =>
|
required int wordCount,
|
||||||
await lib_monero.WowneroWallet.create(
|
}) async {
|
||||||
|
final lib_monero.WowneroSeedType type;
|
||||||
|
switch (wordCount) {
|
||||||
|
case 14:
|
||||||
|
type = lib_monero.WowneroSeedType.fourteen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
type = lib_monero.WowneroSeedType.sixteen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 25:
|
||||||
|
type = lib_monero.WowneroSeedType.twentyFive;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Exception("Invalid mnemonic word count: $wordCount");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await lib_monero.WowneroWallet.create(
|
||||||
path: path,
|
path: path,
|
||||||
password: password,
|
password: password,
|
||||||
seedType: lib_monero.WowneroSeedType
|
seedType: type,
|
||||||
.fourteen, // TODO: check we want to actually use 14 here
|
|
||||||
overrideDeprecated14WordSeedException: true,
|
overrideDeprecated14WordSeedException: true,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<lib_monero.Wallet> getRestoredWallet({
|
Future<lib_monero.Wallet> getRestoredWallet({
|
||||||
|
|
|
@ -142,6 +142,7 @@ abstract class LibMoneroWallet<T extends CryptonoteCurrency>
|
||||||
Future<lib_monero.Wallet> getCreatedWallet({
|
Future<lib_monero.Wallet> getCreatedWallet({
|
||||||
required String path,
|
required String path,
|
||||||
required String password,
|
required String password,
|
||||||
|
required int wordCount,
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<lib_monero.Wallet> getRestoredWallet({
|
Future<lib_monero.Wallet> getRestoredWallet({
|
||||||
|
@ -313,19 +314,26 @@ abstract class LibMoneroWallet<T extends CryptonoteCurrency>
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> init({bool? isRestore}) async {
|
Future<void> init({bool? isRestore, int? wordCount}) async {
|
||||||
final path = await pathForWallet(
|
final path = await pathForWallet(
|
||||||
name: walletId,
|
name: walletId,
|
||||||
type: compatType,
|
type: compatType,
|
||||||
);
|
);
|
||||||
if (!(walletExists(path)) && isRestore != true) {
|
if (!(walletExists(path)) && isRestore != true) {
|
||||||
|
if (wordCount == null) {
|
||||||
|
throw Exception("Missing word count for new xmr/wow wallet!");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
final password = generatePassword();
|
final password = generatePassword();
|
||||||
await secureStorageInterface.write(
|
await secureStorageInterface.write(
|
||||||
key: lib_monero_compat.libMoneroWalletPasswordKey(walletId),
|
key: lib_monero_compat.libMoneroWalletPasswordKey(walletId),
|
||||||
value: password,
|
value: password,
|
||||||
);
|
);
|
||||||
final wallet = await getCreatedWallet(path: path, password: password);
|
final wallet = await getCreatedWallet(
|
||||||
|
path: path,
|
||||||
|
password: password,
|
||||||
|
wordCount: wordCount,
|
||||||
|
);
|
||||||
|
|
||||||
final height = wallet.getRefreshFromBlockHeight();
|
final height = wallet.getRefreshFromBlockHeight();
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,7 @@
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:fullBackupContent="false"
|
android:fullBackupContent="false">
|
||||||
android:extractNativeLibs="true">
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
|
|
Loading…
Reference in a new issue