mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-06 18:59:24 +00:00
feat: WIP UI updates, add a MultisigCoordinator view
TODO: disable "Continue" button on setup view unless all inputs have values. Auto-fill first input in Coordinator view. Add walletId params as necessary in order to get relevant metadata
This commit is contained in:
parent
47525fb301
commit
53901ef6a5
7 changed files with 450 additions and 112 deletions
|
@ -0,0 +1,373 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../../themes/stack_colors.dart';
|
||||
import '../../../../utilities/text_styles.dart';
|
||||
import '../../../../widgets/background.dart';
|
||||
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import '../../../widgets/desktop/primary_button.dart';
|
||||
import '../../../widgets/desktop/secondary_button.dart';
|
||||
import '../../../widgets/icon_widgets/copy_icon.dart';
|
||||
import '../../../widgets/icon_widgets/qrcode_icon.dart';
|
||||
|
||||
final multisigCoordinatorStateProvider =
|
||||
StateNotifierProvider<MultisigCoordinatorState, MultisigCoordinatorData>(
|
||||
(ref) {
|
||||
return MultisigCoordinatorState();
|
||||
});
|
||||
|
||||
class MultisigCoordinatorData {
|
||||
const MultisigCoordinatorData({
|
||||
this.threshold = 2,
|
||||
this.totalCosigners = 3,
|
||||
this.coinType = 0, // Bitcoin mainnet.
|
||||
this.accountIndex = 0,
|
||||
this.scriptType = MultisigScriptType.nativeSegwit,
|
||||
this.cosignerXpubs = const [],
|
||||
});
|
||||
|
||||
final int threshold;
|
||||
final int totalCosigners;
|
||||
final int coinType;
|
||||
final int accountIndex;
|
||||
final MultisigScriptType scriptType;
|
||||
final List<String> cosignerXpubs;
|
||||
|
||||
MultisigCoordinatorData copyWith({
|
||||
int? threshold,
|
||||
int? totalCosigners,
|
||||
int? coinType,
|
||||
int? accountIndex,
|
||||
MultisigScriptType? scriptType,
|
||||
List<String>? cosignerXpubs,
|
||||
}) {
|
||||
return MultisigCoordinatorData(
|
||||
threshold: threshold ?? this.threshold,
|
||||
totalCosigners: totalCosigners ?? this.totalCosigners,
|
||||
coinType: coinType ?? this.coinType,
|
||||
accountIndex: accountIndex ?? this.accountIndex,
|
||||
scriptType: scriptType ?? this.scriptType,
|
||||
cosignerXpubs: cosignerXpubs ?? this.cosignerXpubs,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'threshold': threshold,
|
||||
'totalCosigners': totalCosigners,
|
||||
'coinType': coinType,
|
||||
'accountIndex': accountIndex,
|
||||
'scriptType': scriptType.index,
|
||||
'cosignerXpubs': cosignerXpubs,
|
||||
};
|
||||
|
||||
factory MultisigCoordinatorData.fromJson(Map<String, dynamic> json) {
|
||||
return MultisigCoordinatorData(
|
||||
threshold: json['threshold'] as int,
|
||||
totalCosigners: json['totalCosigners'] as int,
|
||||
coinType: json['coinType'] as int,
|
||||
accountIndex: json['accountIndex'] as int,
|
||||
scriptType: MultisigScriptType.values[json['scriptType'] as int],
|
||||
cosignerXpubs: (json['cosignerXpubs'] as List).cast<String>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum MultisigScriptType {
|
||||
legacy, // P2SH.
|
||||
segwit, // P2SH-P2WSH.
|
||||
nativeSegwit, // P2WSH.
|
||||
}
|
||||
|
||||
class MultisigCoordinatorState extends StateNotifier<MultisigCoordinatorData> {
|
||||
MultisigCoordinatorState() : super(const MultisigCoordinatorData());
|
||||
|
||||
void updateThreshold(int threshold) {
|
||||
state = state.copyWith(threshold: threshold);
|
||||
}
|
||||
|
||||
void updateTotalCosigners(int total) {
|
||||
state = state.copyWith(totalCosigners: total);
|
||||
}
|
||||
|
||||
void updateScriptType(MultisigScriptType type) {
|
||||
state = state.copyWith(scriptType: type);
|
||||
}
|
||||
|
||||
void addCosignerXpub(String xpub) {
|
||||
if (state.cosignerXpubs.length < state.totalCosigners) {
|
||||
state = state.copyWith(
|
||||
cosignerXpubs: [...state.cosignerXpubs, xpub],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MultisigCoordinatorView extends ConsumerStatefulWidget {
|
||||
const MultisigCoordinatorView({
|
||||
super.key,
|
||||
required this.totalCosigners,
|
||||
required this.threshold,
|
||||
});
|
||||
|
||||
final int totalCosigners;
|
||||
final int threshold;
|
||||
|
||||
static const String routeName = "/multisigCoordinator";
|
||||
|
||||
@override
|
||||
ConsumerState<MultisigCoordinatorView> createState() =>
|
||||
_MultisigSetupViewState();
|
||||
}
|
||||
|
||||
class _MultisigSetupViewState extends ConsumerState<MultisigCoordinatorView> {
|
||||
final List<TextEditingController> xpubControllers = [];
|
||||
// bool _isNfcAvailable = false;
|
||||
// String _nfcStatus = 'Checking NFC availability...';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Initialize controllers.
|
||||
for (int i = 0; i < widget.totalCosigners; i++) {
|
||||
xpubControllers.add(TextEditingController());
|
||||
}
|
||||
|
||||
// _checkNfcAvailability();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
for (final controller in xpubControllers) {
|
||||
controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Future<void> _checkNfcAvailability() async {
|
||||
// try {
|
||||
// final availability = await NfcManager.instance.isAvailable();
|
||||
// setState(() {
|
||||
// _isNfcAvailable = availability;
|
||||
// _nfcStatus = _isNfcAvailable
|
||||
// ? 'NFC is available'
|
||||
// : 'NFC is not available on this device';
|
||||
// });
|
||||
// } catch (e) {
|
||||
// setState(() {
|
||||
// _nfcStatus = 'Error checking NFC: $e';
|
||||
// _isNfcAvailable = false;
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Future<void> _startNfcSession() async {
|
||||
// if (!_isNfcAvailable) return;
|
||||
//
|
||||
// setState(() => _nfcStatus = 'Ready to exchange information...');
|
||||
//
|
||||
// try {
|
||||
// await NfcManager.instance.startSession(
|
||||
// onDiscovered: (tag) async {
|
||||
// try {
|
||||
// final ndef = Ndef.from(tag);
|
||||
//
|
||||
// if (ndef == null) {
|
||||
// setState(() => _nfcStatus = 'Tag is not NDEF compatible');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final setupData = ref.watch(multisigSetupStateProvider);
|
||||
//
|
||||
// if (ndef.isWritable) {
|
||||
// final message = NdefMessage([
|
||||
// NdefRecord.createMime(
|
||||
// 'application/x-multisig-setup',
|
||||
// Uint8List.fromList(
|
||||
// utf8.encode(jsonEncode(setupData.toJson()))),
|
||||
// ),
|
||||
// ]);
|
||||
//
|
||||
// try {
|
||||
// await ndef.write(message);
|
||||
// setState(
|
||||
// () => _nfcStatus = 'Configuration shared successfully');
|
||||
// } catch (e) {
|
||||
// setState(
|
||||
// () => _nfcStatus = 'Failed to share configuration: $e');
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// await NfcManager.instance.stopSession();
|
||||
// } catch (e) {
|
||||
// setState(() => _nfcStatus = 'Error during NFC exchange: $e');
|
||||
// await NfcManager.instance.stopSession();
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
// } catch (e) {
|
||||
// setState(() => _nfcStatus = 'Error: $e');
|
||||
// await NfcManager.instance.stopSession();
|
||||
// }
|
||||
// }
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Background(
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 75));
|
||||
}
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
"Enter cosigner xpubs",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
titleSpacing: 0,
|
||||
),
|
||||
body: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SingleChildScrollView(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: constraints.maxHeight,
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Enter the extended public key (xpub) for each cosigner. "
|
||||
"These can be obtained from each participant's wallet.",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Generate input fields for each cosigner
|
||||
for (int i = 0; i < widget.totalCosigners; i++)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Cosigner ${i + 1} xpub",
|
||||
style:
|
||||
STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: xpubControllers[i],
|
||||
decoration: InputDecoration(
|
||||
hintText: "Enter xpub",
|
||||
hintStyle:
|
||||
STextStyles.fieldLabel(context),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value.isNotEmpty) {
|
||||
ref
|
||||
.read(
|
||||
multisigCoordinatorStateProvider
|
||||
.notifier)
|
||||
.addCosignerXpub(value);
|
||||
}
|
||||
setState(
|
||||
() {}); // Trigger rebuild to update button state.
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
SecondaryButton(
|
||||
width: 44,
|
||||
buttonHeight: ButtonHeight.xl,
|
||||
icon: QrCodeIcon(
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextSecondary,
|
||||
),
|
||||
onPressed: () {
|
||||
// TODO: Implement QR code scanning
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
SecondaryButton(
|
||||
width: 44,
|
||||
buttonHeight: ButtonHeight.xl,
|
||||
icon: CopyIcon(
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextSecondary,
|
||||
),
|
||||
onPressed: () async {
|
||||
final data = await Clipboard.getData(
|
||||
'text/plain');
|
||||
if (data?.text != null) {
|
||||
xpubControllers[i].text =
|
||||
data!.text!;
|
||||
ref
|
||||
.read(
|
||||
multisigCoordinatorStateProvider
|
||||
.notifier)
|
||||
.addCosignerXpub(data.text!);
|
||||
setState(
|
||||
() {}); // Trigger rebuild to update button state.
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const Spacer(),
|
||||
|
||||
PrimaryButton(
|
||||
label: "Create multisignature account",
|
||||
enabled: xpubControllers.every(
|
||||
(controller) => controller.text.isNotEmpty),
|
||||
onPressed: () {
|
||||
// TODO.
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import '../../../widgets/custom_buttons/blue_text_button.dart';
|
|||
import '../../../widgets/desktop/primary_button.dart';
|
||||
import '../../../widgets/dialogs/simple_mobile_dialog.dart';
|
||||
import '../../../widgets/stack_dialog.dart';
|
||||
import 'multisig_coordinator_view.dart';
|
||||
|
||||
final multisigSetupStateProvider =
|
||||
StateNotifierProvider<MultisigSetupState, MultisigSetupData>((ref) {
|
||||
|
@ -110,8 +111,13 @@ class MultisigSetupState extends StateNotifier<MultisigSetupData> {
|
|||
class MultisigSetupView extends ConsumerStatefulWidget {
|
||||
const MultisigSetupView({
|
||||
super.key,
|
||||
this.totalCosigners,
|
||||
this.threshold,
|
||||
});
|
||||
|
||||
final int? totalCosigners;
|
||||
final int? threshold;
|
||||
|
||||
static const String routeName = "/multisigSetup";
|
||||
|
||||
@override
|
||||
|
@ -119,81 +125,25 @@ class MultisigSetupView extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _MultisigSetupViewState extends ConsumerState<MultisigSetupView> {
|
||||
// bool _isNfcAvailable = false;
|
||||
// String _nfcStatus = 'Checking NFC availability...';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// _checkNfcAvailability();
|
||||
}
|
||||
|
||||
// Future<void> _checkNfcAvailability() async {
|
||||
// try {
|
||||
// final availability = await NfcManager.instance.isAvailable();
|
||||
// setState(() {
|
||||
// _isNfcAvailable = availability;
|
||||
// _nfcStatus = _isNfcAvailable
|
||||
// ? 'NFC is available'
|
||||
// : 'NFC is not available on this device';
|
||||
// });
|
||||
// } catch (e) {
|
||||
// setState(() {
|
||||
// _nfcStatus = 'Error checking NFC: $e';
|
||||
// _isNfcAvailable = false;
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Future<void> _startNfcSession() async {
|
||||
// if (!_isNfcAvailable) return;
|
||||
//
|
||||
// setState(() => _nfcStatus = 'Ready to exchange information...');
|
||||
//
|
||||
// try {
|
||||
// await NfcManager.instance.startSession(
|
||||
// onDiscovered: (tag) async {
|
||||
// try {
|
||||
// final ndef = Ndef.from(tag);
|
||||
//
|
||||
// if (ndef == null) {
|
||||
// setState(() => _nfcStatus = 'Tag is not NDEF compatible');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final setupData = ref.watch(multisigSetupStateProvider);
|
||||
//
|
||||
// if (ndef.isWritable) {
|
||||
// final message = NdefMessage([
|
||||
// NdefRecord.createMime(
|
||||
// 'application/x-multisig-setup',
|
||||
// Uint8List.fromList(
|
||||
// utf8.encode(jsonEncode(setupData.toJson()))),
|
||||
// ),
|
||||
// ]);
|
||||
//
|
||||
// try {
|
||||
// await ndef.write(message);
|
||||
// setState(
|
||||
// () => _nfcStatus = 'Configuration shared successfully');
|
||||
// } catch (e) {
|
||||
// setState(
|
||||
// () => _nfcStatus = 'Failed to share configuration: $e');
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// await NfcManager.instance.stopSession();
|
||||
// } catch (e) {
|
||||
// setState(() => _nfcStatus = 'Error during NFC exchange: $e');
|
||||
// await NfcManager.instance.stopSession();
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
// } catch (e) {
|
||||
// setState(() => _nfcStatus = 'Error: $e');
|
||||
// await NfcManager.instance.stopSession();
|
||||
// }
|
||||
// }
|
||||
// Initialize participants count if provided.
|
||||
if (widget.totalCosigners != null) {
|
||||
_participantsCount = widget.totalCosigners!;
|
||||
_participantsController.text = widget.totalCosigners!.toString();
|
||||
// Initialize the controllers list.
|
||||
for (int i = 0; i < widget.totalCosigners!; i++) {
|
||||
controllers.add(TextEditingController());
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize threshold if provided.
|
||||
if (widget.threshold != null) {
|
||||
_thresholdController.text = widget.threshold!.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays a short explanation dialog about musig.
|
||||
Future<void> _showMultisigInfoDialog() async {
|
||||
|
@ -557,7 +507,7 @@ class _MultisigSetupViewState extends ConsumerState<MultisigSetupView> {
|
|||
|
||||
// TODO: Push button to bottom of page.
|
||||
PrimaryButton(
|
||||
label: "Create multisignature account",
|
||||
label: "Continue",
|
||||
onPressed: () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
@ -575,34 +525,15 @@ class _MultisigSetupViewState extends ConsumerState<MultisigSetupView> {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO: Adapt the FROST config steps UI.
|
||||
// final config = Frost.createMultisigConfig(
|
||||
// name: controllers.first.text.trim(),
|
||||
// threshold: int.parse(_thresholdController.text),
|
||||
// participants:
|
||||
// controllers.map((e) => e.text.trim()).toList(),
|
||||
// );
|
||||
//
|
||||
// ref.read(pFrostMyName.notifier).state =
|
||||
// controllers.first.text.trim();
|
||||
// ref.read(pFrostMultisigConfig.notifier).state = config;
|
||||
//
|
||||
// ref.read(pFrostScaffoldArgs.state).state = (
|
||||
// info: (
|
||||
// walletName: widget.walletName,
|
||||
// frostCurrency: widget.frostCurrency,
|
||||
// ),
|
||||
// walletId: null,
|
||||
// stepRoutes: FrostRouteGenerator.createNewConfigStepRoutes,
|
||||
// frostInterruptionDialogType:
|
||||
// FrostInterruptionDialogType.walletCreation,
|
||||
// parentNav: Navigator.of(context),
|
||||
// callerRouteName: CreateNewFrostMsWalletView.routeName,
|
||||
// );
|
||||
//
|
||||
// await Navigator.of(context).pushNamed(
|
||||
// FrostStepScaffold.routeName,
|
||||
// );
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (context) => MultisigCoordinatorView(
|
||||
totalCosigners:
|
||||
int.parse(_participantsController.text),
|
||||
threshold: int.parse(_thresholdController.text),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
|
@ -98,7 +98,7 @@ import '../settings_views/wallet_settings_view/wallet_network_settings_view/wall
|
|||
import '../settings_views/wallet_settings_view/wallet_settings_view.dart';
|
||||
import '../special/firo_rescan_recovery_error_dialog.dart';
|
||||
import '../token_view/my_tokens_view.dart';
|
||||
import 'multisig_setup_view/multisig_setup_view.dart';
|
||||
import 'multisig_coordinator_view/multisig_setup_view.dart';
|
||||
import 'sub_widgets/transactions_list.dart';
|
||||
import 'sub_widgets/wallet_summary.dart';
|
||||
import 'transaction_views/all_transactions_view.dart';
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/multisig_setup_view/multisig_setup_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/multisig_coordinator_view/multisig_coordinator_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/multisig_coordinator_view/multisig_setup_view.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
import 'models/add_wallet_list_entity/add_wallet_list_entity.dart';
|
||||
|
@ -2157,13 +2158,41 @@ class RouteGenerator {
|
|||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case MultisigSetupView.routeName:
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => const MultisigSetupView(),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
if (args is Tuple2<int?, int?>) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => MultisigSetupView(
|
||||
totalCosigners: args.item1,
|
||||
threshold: args.item2,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => const MultisigSetupView(),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case MultisigCoordinatorView.routeName:
|
||||
if (args is Tuple2<int, int>) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => MultisigCoordinatorView(
|
||||
totalCosigners: args.item1,
|
||||
threshold: args.item2,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
// == Desktop specific routes ============================================
|
||||
|
|
|
@ -6,12 +6,16 @@ import '../../../utilities/amount/amount.dart';
|
|||
import '../../../utilities/default_nodes.dart';
|
||||
import '../../../utilities/enums/derive_path_type_enum.dart';
|
||||
import '../crypto_currency.dart';
|
||||
import '../interfaces/bip48_currency_interface.dart';
|
||||
import '../interfaces/electrumx_currency_interface.dart';
|
||||
import '../interfaces/paynym_currency_interface.dart';
|
||||
import '../intermediate/bip39_hd_currency.dart';
|
||||
|
||||
class Bitcoin extends Bip39HDCurrency
|
||||
with ElectrumXCurrencyInterface, PaynymCurrencyInterface {
|
||||
with
|
||||
ElectrumXCurrencyInterface,
|
||||
PaynymCurrencyInterface,
|
||||
BIP48CurrencyInterface {
|
||||
Bitcoin(super.network) {
|
||||
_idMain = "bitcoin";
|
||||
_uriScheme = "bitcoin";
|
||||
|
|
|
@ -273,6 +273,8 @@ class BIP48Wallet<T extends Bip39HDCurrency> extends Wallet<T>
|
|||
|
||||
TransactionType type;
|
||||
TransactionSubType subType = TransactionSubType.none;
|
||||
// Will BIP48 wallets enjoy BIP47 compatibility? We should add vectors
|
||||
// for this if so--do any wallets implement such functionality?
|
||||
if (outputs.length > 1 && inputs.isNotEmpty) {
|
||||
for (int i = 0; i < outputs.length; i++) {
|
||||
final List<String>? scriptChunks =
|
||||
|
@ -465,14 +467,13 @@ class BIP48Wallet<T extends Bip39HDCurrency> extends Wallet<T>
|
|||
|
||||
@override
|
||||
Future<TxData> prepareSend({required TxData txData}) {
|
||||
// TODO: implement prepareSendpu
|
||||
// TODO: implement prepareSend
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> recover({
|
||||
required bool isRescan,
|
||||
String? serializedKeys,
|
||||
String? multisigConfig,
|
||||
}) async {
|
||||
// TODO.
|
||||
|
|
Loading…
Reference in a new issue