lots of fixes + finish up seed derivation

This commit is contained in:
fosse 2023-08-16 10:24:20 -04:00
parent 2fb43e8b28
commit cd7f636558
9 changed files with 209 additions and 144 deletions

View file

@ -232,25 +232,26 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
@override @override
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async { Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async {
throw UnimplementedError("restoreFromKeys"); if (credentials.seedKey.contains(' ')) {
throw Exception("Invalid key!");
} else {
if (credentials.seedKey.length != 64 && credentials.seedKey.length != 128) {
throw Exception("Invalid key length!");
}
}
// TODO: mnemonic can't be derived from the seedKey in the nano standard derivation
// which complicates things
// DerivationType derivationType = credentials.derivationType ?? await compareDerivationMethods(seedKey: credentials.seedKey); DerivationType derivationType = credentials.derivationType ?? DerivationType.nano;
// String? mnemonic; credentials.walletInfo!.derivationType = derivationType;
// final nanoWalletInfo = NanoWalletInfo(
// walletInfo: credentials.walletInfo!, final wallet = await NanoWallet(
// derivationType: derivationType, password: credentials.password!,
// ); mnemonic: credentials.seedKey,// we can't derive the mnemonic from the key in all cases
// final wallet = await NanoWallet( walletInfo: credentials.walletInfo!,
// password: credentials.password!, );
// mnemonic: mnemonic ?? "", // we can't derive the mnemonic from the key in all cases await wallet.init();
// walletInfo: nanoWalletInfo, await wallet.save();
// ); return wallet;
// await wallet.init();
// await wallet.save();
// return wallet;
} }
@override @override

View file

@ -127,6 +127,31 @@ class CWNano extends Nano {
); );
} }
@override
WalletCredentials createNanoRestoreWalletFromKeysCredentials({
required String name,
required String password,
required String seedKey,
DerivationType? derivationType,
}) {
if (derivationType == null) {
// figure out the derivation type as best we can, otherwise set it to "unknown"
if (seedKey.length == 64) {
derivationType = DerivationType.nano;
} else {
derivationType = DerivationType.unknown;
}
}
return NanoRestoreWalletFromKeysCredentials(
name: name,
password: password,
seedKey: seedKey,
derivationType: derivationType,
);
}
@override @override
TransactionHistoryBase getTransactionHistory(Object wallet) { TransactionHistoryBase getTransactionHistory(Object wallet) {
throw UnimplementedError(); throw UnimplementedError();

View file

@ -12,9 +12,6 @@ import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/output_info.dart'; import 'package:cw_core/output_info.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:cw_nano/api/wallet.dart' as nano_wallet_api;
import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_wallet_creation_credentials.dart';
import 'package:cw_nano/nano_transaction_credentials.dart'; import 'package:cw_nano/nano_transaction_credentials.dart';
part 'cw_nano.dart'; part 'cw_nano.dart';
@ -44,6 +41,13 @@ abstract class Nano {
DerivationType? derivationType, DerivationType? derivationType,
}); });
WalletCredentials createNanoRestoreWalletFromKeysCredentials({
required String name,
required String password,
required String seedKey,
DerivationType? derivationType,
});
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex); String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
void onStartup(); void onStartup();

View file

@ -38,7 +38,7 @@ class WalletRestoreChooseDerivationPage extends BasePage {
} else if (snapshot.hasError) { } else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}'); return Text('Error: ${snapshot.error}');
} else if (!snapshot.hasData || snapshot.data!.isEmpty) { } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Text('No derivations available'); return Text('Error! No derivations available!');
} else { } else {
return ListView.separated( return ListView.separated(
shrinkWrap: true, shrinkWrap: true,

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/src/widgets/seed_widget.dart';
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -14,16 +15,17 @@ import 'package:cake_wallet/entities/generate_name.dart';
class WalletRestoreFromKeysFrom extends StatefulWidget { class WalletRestoreFromKeysFrom extends StatefulWidget {
WalletRestoreFromKeysFrom({ WalletRestoreFromKeysFrom({
required this.walletRestoreViewModel, required this.walletRestoreViewModel,
required this.onSpendKeyChange,
Key? key, Key? key,
this.onHeightOrDateEntered,}) this.onHeightOrDateEntered,
: super(key: key); }) : super(key: key);
final Function(bool)? onHeightOrDateEntered; final Function(bool)? onHeightOrDateEntered;
final WalletRestoreViewModel walletRestoreViewModel; final WalletRestoreViewModel walletRestoreViewModel;
final void Function(String)? onSpendKeyChange;
@override @override
WalletRestoreFromKeysFromState createState() => WalletRestoreFromKeysFromState createState() => WalletRestoreFromKeysFromState();
WalletRestoreFromKeysFromState();
} }
class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> { class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
@ -44,6 +46,15 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
final TextEditingController spendKeyController; final TextEditingController spendKeyController;
final TextEditingController nameTextEditingController; final TextEditingController nameTextEditingController;
@override
void initState() {
super.initState();
spendKeyController.addListener(() {
widget.onSpendKeyChange?.call(spendKeyController.text);
});
}
@override @override
void dispose() { void dispose() {
nameController.dispose(); nameController.dispose();
@ -74,9 +85,8 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
setState(() { setState(() {
nameTextEditingController.text = rName; nameTextEditingController.text = rName;
nameTextEditingController.selection = nameTextEditingController.selection = TextSelection.fromPosition(
TextSelection.fromPosition(TextPosition( TextPosition(offset: nameTextEditingController.text.length));
offset: nameTextEditingController.text.length));
}); });
}, },
icon: Container( icon: Container(
@ -89,10 +99,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
height: 34, height: 34,
child: Image.asset( child: Image.asset(
'assets/images/refresh_icon.png', 'assets/images/refresh_icon.png',
color: Theme.of(context) color: Theme.of(context).primaryTextTheme!.headlineMedium!.decorationColor!,
.primaryTextTheme!
.headlineMedium!
.decorationColor!,
), ),
), ),
), ),
@ -100,28 +107,36 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
], ],
), ),
Container(height: 20), Container(height: 20),
BaseTextFormField( if (widget.walletRestoreViewModel.hasMultipleKeys) ...[
controller: addressController, BaseTextFormField(
keyboardType: TextInputType.multiline, controller: addressController,
maxLines: null, keyboardType: TextInputType.multiline,
hintText: S.of(context).restore_address), maxLines: null,
Container( hintText: S.of(context).restore_address),
padding: EdgeInsets.only(top: 20.0), Container(
child: BaseTextFormField( padding: EdgeInsets.only(top: 20.0),
controller: viewKeyController, child: BaseTextFormField(
hintText: S.of(context).restore_view_key_private, controller: viewKeyController,
maxLines: null)), hintText: S.of(context).restore_view_key_private,
Container( maxLines: null)),
padding: EdgeInsets.only(top: 20.0), Container(
child: BaseTextFormField( padding: EdgeInsets.only(top: 20.0),
controller: spendKeyController, child: BaseTextFormField(
hintText: S.of(context).restore_spend_key_private, controller: spendKeyController,
maxLines: null)), hintText: S.of(context).restore_spend_key_private,
BlockchainHeightWidget( maxLines: null)),
key: blockchainHeightKey, BlockchainHeightWidget(
hasDatePicker: widget.walletRestoreViewModel.type != WalletType.haven, key: blockchainHeightKey,
onHeightChange: (_) => null, hasDatePicker: widget.walletRestoreViewModel.type != WalletType.haven,
onHeightOrDateEntered: widget.onHeightOrDateEntered) onHeightChange: (_) => null,
onHeightOrDateEntered: widget.onHeightOrDateEntered)
] else
Container(
padding: EdgeInsets.only(top: 20.0),
child: BaseTextFormField(
controller: spendKeyController,
hintText: S.of(context).restore_spend_key_private,
maxLines: null)),
]), ]),
)); ));
} }

View file

@ -73,21 +73,13 @@ class WalletRestorePage extends BasePage {
} }
})); }));
break; break;
case WalletRestoreMode.seedKey:
_pages.add(WalletRestoreFromSeedKeyForm(
displayBlockHeightSelector: walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
type: walletRestoreViewModel.type,
key: walletRestoreFromSeedKeyFormKey,
onSeedChange: (String seed) {
walletRestoreViewModel.isButtonEnabled = _isValidSeedKey();
},
));
break;
case WalletRestoreMode.keys: case WalletRestoreMode.keys:
_pages.add(WalletRestoreFromKeysFrom( _pages.add(WalletRestoreFromKeysFrom(
key: walletRestoreFromKeysFormKey, key: walletRestoreFromKeysFormKey,
walletRestoreViewModel: walletRestoreViewModel, walletRestoreViewModel: walletRestoreViewModel,
onSpendKeyChange: (String seed) {
walletRestoreViewModel.isButtonEnabled = _isValidSeedKey();
},
onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value)); onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value));
break; break;
default: default:
@ -176,14 +168,8 @@ class WalletRestorePage extends BasePage {
Expanded( Expanded(
child: PageView.builder( child: PageView.builder(
onPageChanged: (page) { onPageChanged: (page) {
if (walletRestoreViewModel.type == WalletType.nano || walletRestoreViewModel.mode =
walletRestoreViewModel.type == WalletType.banano) { page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
walletRestoreViewModel.mode =
page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.seedKey;
} else {
walletRestoreViewModel.mode =
page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
}
}, },
controller: _controller, controller: _controller,
itemCount: _pages.length, itemCount: _pages.length,
@ -254,8 +240,7 @@ class WalletRestorePage extends BasePage {
} }
bool _isValidSeedKey() { bool _isValidSeedKey() {
final seedKey = final seedKey = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
walletRestoreFromSeedKeyFormKey.currentState!.seedWidgetStateKey.currentState!.text;
if (seedKey.length != 64 && seedKey.length != 128) { if (seedKey.length != 64 && seedKey.length != 128) {
return false; return false;
@ -279,16 +264,20 @@ class WalletRestorePage extends BasePage {
credentials['name'] = credentials['name'] =
walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text; walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text;
} else if (walletRestoreViewModel.mode == WalletRestoreMode.keys) { } else if (walletRestoreViewModel.mode == WalletRestoreMode.keys) {
credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text; if (!walletRestoreViewModel.hasMultipleKeys) {
credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text; credentials['name'] =
credentials['spendKey'] = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text; walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
credentials['height'] = credentials['seedKey'] = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height; } else {
credentials['name'] = credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text;
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text; credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
} else if (walletRestoreViewModel.mode == WalletRestoreMode.seedKey) { credentials['spendKey'] =
credentials['seedKey'] = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
walletRestoreFromSeedKeyFormKey.currentState!.seedWidgetStateKey.currentState!.text; credentials['height'] =
walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height;
credentials['name'] =
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
}
} }
credentials['derivationType'] = this.derivationType; credentials['derivationType'] = this.derivationType;
@ -299,7 +288,7 @@ class WalletRestorePage extends BasePage {
Future<void> _confirmForm(BuildContext context) async { Future<void> _confirmForm(BuildContext context) async {
// Dismissing all visible keyboard to provide context for navigation // Dismissing all visible keyboard to provide context for navigation
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
late BuildContext? formContext; late BuildContext? formContext;
late GlobalKey<FormState>? formKey; late GlobalKey<FormState>? formKey;
late String name; late String name;
@ -311,10 +300,6 @@ class WalletRestorePage extends BasePage {
formContext = walletRestoreFromKeysFormKey.currentContext; formContext = walletRestoreFromKeysFormKey.currentContext;
formKey = walletRestoreFromKeysFormKey.currentState!.formKey; formKey = walletRestoreFromKeysFormKey.currentState!.formKey;
name = walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.value.text; name = walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.value.text;
} else if (walletRestoreViewModel.mode == WalletRestoreMode.seedKey) {
formContext = walletRestoreFromSeedKeyFormKey.currentContext;
formKey = walletRestoreFromSeedKeyFormKey.currentState!.formKey;
name = walletRestoreFromSeedKeyFormKey.currentState!.nameTextEditingController.value.text;
} }
if (!formKey!.currentState!.validate()) { if (!formKey!.currentState!.validate()) {
@ -330,7 +315,8 @@ class WalletRestorePage extends BasePage {
List<DerivationType> derivationTypes = List<DerivationType> derivationTypes =
await walletRestoreViewModel.getDerivationType(_credentials()); await walletRestoreViewModel.getDerivationType(_credentials());
if (derivationTypes[0] == DerivationType.unknown || derivationTypes.length > 0) {
if (derivationTypes[0] == DerivationType.unknown || derivationTypes.length > 1) {
// push screen to choose the derivation type: // push screen to choose the derivation type:
var derivationType = await Navigator.of(context) var derivationType = await Navigator.of(context)
.pushNamed(Routes.restoreWalletChooseDerivation, arguments: _credentials()) .pushNamed(Routes.restoreWalletChooseDerivation, arguments: _credentials())
@ -340,12 +326,19 @@ class WalletRestorePage extends BasePage {
return; return;
} }
this.derivationType = derivationType; this.derivationType = derivationType;
} else {
this.derivationType = derivationTypes[0];
} }
walletRestoreViewModel.state = InitialExecutionState(); walletRestoreViewModel.state = InitialExecutionState();
// todo: re-enable // todo: re-enable
walletRestoreViewModel.create(options: _credentials()); try {
walletRestoreViewModel.create(options: _credentials());
} catch (e) {
print(e);
rethrow;
}
} }
Future<void> showNameExistsAlert(BuildContext context) { Future<void> showNameExistsAlert(BuildContext context) {

View file

@ -33,33 +33,43 @@ abstract class WalletRestoreChooseDerivationViewModelBase with Store {
Future<List<Derivation>> get derivations async { Future<List<Derivation>> get derivations async {
var list = <Derivation>[]; var list = <Derivation>[];
switch ((await getIt.get<AppStore>().wallet!.type)) { switch ((await getIt.get<AppStore>().wallet!.type)) {
case WalletType.nano: case WalletType.nano:
var seed = credentials['seed'] as String; String? mnemonic = credentials['seed'] as String?;
var bip39Info = String? seedKey = credentials['seedKey'] as String?;
await NanoWalletService.getInfoFromSeedOrMnemonic(DerivationType.bip39, mnemonic: seed); var bip39Info = await NanoWalletService.getInfoFromSeedOrMnemonic(
var standardInfo =
await NanoWalletService.getInfoFromSeedOrMnemonic(DerivationType.nano, mnemonic: seed);
list.add(Derivation(
NanoUtil.getRawAsUsableString(standardInfo["balance"] as String, NanoUtil.rawPerNano),
standardInfo["address"] as String,
DerivationType.nano,
int.parse(
standardInfo["confirmation_height"] as String,
),
));
list.add(Derivation(
NanoUtil.getRawAsUsableString(bip39Info["balance"] as String, NanoUtil.rawPerNano),
bip39Info["address"] as String,
DerivationType.bip39, DerivationType.bip39,
int.parse( mnemonic: mnemonic,
bip39Info["confirmation_height"] as String, seedKey: seedKey,
), );
)); var standardInfo = await NanoWalletService.getInfoFromSeedOrMnemonic(
DerivationType.nano,
mnemonic: mnemonic,
seedKey: seedKey,
);
if (standardInfo["address"] != null) {
list.add(Derivation(
NanoUtil.getRawAsUsableString(standardInfo["balance"] as String, NanoUtil.rawPerNano),
standardInfo["address"] as String,
DerivationType.nano,
int.parse(
standardInfo["confirmation_height"] as String,
),
));
}
if (bip39Info["balance"] != null) {
list.add(Derivation(
NanoUtil.getRawAsUsableString(bip39Info["balance"] as String, NanoUtil.rawPerNano),
bip39Info["address"] as String,
DerivationType.bip39,
int.tryParse(
bip39Info["confirmation_height"] as String? ?? "",
) ??
0,
));
}
break; break;
default: default:

View file

@ -28,10 +28,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
: availableModes = (type == WalletType.monero || type == WalletType.haven) : availableModes = (type == WalletType.monero || type == WalletType.haven)
? [WalletRestoreMode.seed, WalletRestoreMode.keys, WalletRestoreMode.txids] ? [WalletRestoreMode.seed, WalletRestoreMode.keys, WalletRestoreMode.txids]
: (type == WalletType.nano || type == WalletType.banano) : (type == WalletType.nano || type == WalletType.banano)
? [WalletRestoreMode.seed, WalletRestoreMode.seedKey] ? [WalletRestoreMode.seed, WalletRestoreMode.keys]
: [WalletRestoreMode.seed], : [WalletRestoreMode.seed],
hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven, hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven, hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
hasMultipleKeys = type != WalletType.nano || type == WalletType.banano,
isButtonEnabled = false, isButtonEnabled = false,
mode = WalletRestoreMode.seed, mode = WalletRestoreMode.seed,
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) { super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) {
@ -46,6 +47,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
final List<WalletRestoreMode> availableModes; final List<WalletRestoreMode> availableModes;
final bool hasSeedLanguageSelector; final bool hasSeedLanguageSelector;
final bool hasBlockchainHeightLanguageSelector; final bool hasBlockchainHeightLanguageSelector;
final bool hasMultipleKeys;
@observable @observable
WalletRestoreMode mode; WalletRestoreMode mode;
@ -61,7 +63,6 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
if (mode == WalletRestoreMode.seed) { if (mode == WalletRestoreMode.seed) {
final seed = options['seed'] as String; final seed = options['seed'] as String;
switch (type) { switch (type) {
case WalletType.monero: case WalletType.monero:
return monero!.createMoneroRestoreWalletFromSeedCredentials( return monero!.createMoneroRestoreWalletFromSeedCredentials(
@ -83,7 +84,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
name: name, name: name,
mnemonic: seed, mnemonic: seed,
password: password, password: password,
derivationType: null, derivationType: options["derivationType"] as DerivationType,
); );
default: default:
break; break;
@ -91,30 +92,41 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
} }
if (mode == WalletRestoreMode.keys) { if (mode == WalletRestoreMode.keys) {
final viewKey = options['viewKey'] as String; if (hasMultipleKeys) {
final spendKey = options['spendKey'] as String; final viewKey = options['viewKey'] as String;
final address = options['address'] as String; final spendKey = options['spendKey'] as String;
final address = options['address'] as String;
if (type == WalletType.monero) { if (type == WalletType.monero) {
return monero!.createMoneroRestoreWalletFromKeysCredentials( return monero!.createMoneroRestoreWalletFromKeysCredentials(
name: name, name: name,
height: height, height: height,
spendKey: spendKey, spendKey: spendKey,
viewKey: viewKey, viewKey: viewKey,
address: address, address: address,
password: password, password: password,
language: 'English'); language: 'English');
} }
if (type == WalletType.haven) { if (type == WalletType.haven) {
return haven!.createHavenRestoreWalletFromKeysCredentials( return haven!.createHavenRestoreWalletFromKeysCredentials(
name: name, name: name,
height: height, height: height,
spendKey: spendKey, spendKey: spendKey,
viewKey: viewKey, viewKey: viewKey,
address: address, address: address,
password: password, password: password,
language: 'English'); language: 'English');
}
} else {
if (type == WalletType.nano) {
return nano!.createNanoRestoreWalletFromKeysCredentials(
name: name,
password: password,
seedKey: options['seedKey'] as String,
derivationType: options["derivationType"] as DerivationType,
);
}
} }
} }
@ -134,7 +146,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
// return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( // return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
// name: name, mnemonic: seed, password: password); // name: name, mnemonic: seed, password: password);
case WalletType.nano: case WalletType.nano:
return await NanoWalletService.compareDerivationMethods(mnemonic: mnemonic, seedKey: seedKey); return await NanoWalletService.compareDerivationMethods(
mnemonic: mnemonic, seedKey: seedKey);
default: default:
break; break;
} }

View file

@ -592,9 +592,6 @@ import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/output_info.dart'; import 'package:cw_core/output_info.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:cw_nano/api/wallet.dart' as nano_wallet_api;
import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_wallet_creation_credentials.dart';
import 'package:cw_nano/nano_transaction_credentials.dart'; import 'package:cw_nano/nano_transaction_credentials.dart';
"""; """;
const nanoCwPart = "part 'cw_nano.dart';"; const nanoCwPart = "part 'cw_nano.dart';";
@ -622,6 +619,13 @@ abstract class Nano {
DerivationType? derivationType, DerivationType? derivationType,
}); });
WalletCredentials createNanoRestoreWalletFromKeysCredentials({
required String name,
required String password,
required String seedKey,
DerivationType? derivationType,
});
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex); String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
void onStartup(); void onStartup();