Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion lib/models/keys/view_only_wallet_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import 'key_data_interface.dart';
enum ViewOnlyWalletType {
cryptonote,
addressOnly,
xPub;
xPub,
spark;
}

sealed class ViewOnlyWalletData with KeyDataInterface {
Expand Down Expand Up @@ -46,6 +47,12 @@ sealed class ViewOnlyWalletData with KeyDataInterface {
jsonEncodedString,
walletId: walletId,
);

case ViewOnlyWalletType.spark:
return SparkViewOnlyWalletData.fromJsonEncodedString(
jsonEncodedString,
walletId: walletId,
);
}
}

Expand Down Expand Up @@ -162,3 +169,34 @@ class ExtendedKeysViewOnlyWalletData extends ViewOnlyWalletData {
],
});
}

class SparkViewOnlyWalletData extends ViewOnlyWalletData {
@override
final type = ViewOnlyWalletType.spark;

final String viewKey;

SparkViewOnlyWalletData({
required super.walletId,
required this.viewKey,
});

static SparkViewOnlyWalletData fromJsonEncodedString(
String jsonEncodedString, {
required String walletId,
}) {
final map = jsonDecode(jsonEncodedString) as Map;
final json = Map<String, dynamic>.from(map);

return SparkViewOnlyWalletData(
walletId: walletId,
viewKey: json["viewKey"] as String,
);
}

@override
String toJsonEncodedString() => jsonEncode({
"type": type.index,
"viewKey": viewKey,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ import '../../../widgets/desktop/desktop_app_bar.dart';
import '../../../widgets/desktop/desktop_scaffold.dart';
import '../../../widgets/desktop/primary_button.dart';
import '../../../widgets/stack_text_field.dart';
import '../../../widgets/toggle.dart';
import '../../../widgets/options.dart';
import '../../home_view/home_view.dart';
import 'confirm_recovery_dialog.dart';
import 'sub_widgets/restore_failed_dialog.dart';
import 'sub_widgets/restore_succeeded_dialog.dart';
import 'sub_widgets/restoring_dialog.dart';
import '../../../wallets/wallet/impl/firo_wallet.dart';

class RestoreViewOnlyWalletView extends ConsumerStatefulWidget {
const RestoreViewOnlyWalletView({
Expand All @@ -68,13 +69,13 @@ class _RestoreViewOnlyWalletViewState
extends ConsumerState<RestoreViewOnlyWalletView> {
late final TextEditingController addressController;
late final TextEditingController viewKeyController;
late final TextEditingController sparkViewKeyController;

late String _currentDropDownValue;
late ViewOnlyWalletType _walletType;

bool _enableRestoreButton = false;
bool _addressOnly = false;

bool _buttonLock = false;
late String _currentDropDownValue;

Future<void> _requestRestore() async {
if (_buttonLock) return;
Expand Down Expand Up @@ -107,21 +108,16 @@ class _RestoreViewOnlyWalletViewState
WalletInfoKeys.isViewOnlyKey: true,
};

final ViewOnlyWalletType viewOnlyWalletType;
ViewOnlyWalletType viewOnlyWalletType = _walletType;
if (widget.coin is Bip39HDCurrency) {
viewOnlyWalletType =
_addressOnly
? ViewOnlyWalletType.addressOnly
: ViewOnlyWalletType.xPub;
} else if (widget.coin is CryptonoteCurrency) {
viewOnlyWalletType = ViewOnlyWalletType.cryptonote;
} else {
throw Exception(
"Unsupported view only wallet currency type found: ${widget.coin.runtimeType}",
);
}
otherDataJson[WalletInfoKeys.viewOnlyTypeIndexKey] =
viewOnlyWalletType.index;
otherDataJson[WalletInfoKeys.viewOnlyTypeIndexKey] = _walletType.index;

if (!Platform.isLinux && !Util.isDesktop) await WakelockPlus.enable();

Expand Down Expand Up @@ -192,6 +188,16 @@ class _RestoreViewOnlyWalletViewState
],
);
break;

case ViewOnlyWalletType.spark:
if (sparkViewKeyController.text.isEmpty) {
throw Exception("Spark View Key is empty");
}
viewOnlyData = SparkViewOnlyWalletData(
walletId: info.walletId,
viewKey: sparkViewKeyController.text,
);
break;
}

var node = ref
Expand Down Expand Up @@ -237,6 +243,10 @@ class _RestoreViewOnlyWalletViewState
await (wallet as XelisWallet).init(isRestore: true);
break;

case const (FiroWallet):
await (wallet as FiroWallet).init();
break;

default:
await wallet.init();
}
Expand Down Expand Up @@ -314,19 +324,23 @@ class _RestoreViewOnlyWalletViewState
super.initState();
addressController = TextEditingController();
viewKeyController = TextEditingController();
sparkViewKeyController = TextEditingController();

if (widget.coin is Bip39HDCurrency) {
_currentDropDownValue =
(widget.coin as Bip39HDCurrency)
.supportedHardenedDerivationPaths
.last;
_currentDropDownValue = (widget.coin as Bip39HDCurrency)
.supportedHardenedDerivationPaths
.last;
_walletType = ViewOnlyWalletType.xPub;
} else if (widget.coin is CryptonoteCurrency) {
_walletType = ViewOnlyWalletType.cryptonote;
}
}

@override
void dispose() {
addressController.dispose();
viewKeyController.dispose();
sparkViewKeyController.dispose();
super.dispose();
}

Expand Down Expand Up @@ -393,23 +407,25 @@ class _RestoreViewOnlyWalletViewState
if (isElectrumX)
SizedBox(
height: isDesktop ? 56 : 48,
width: isDesktop ? 490 : null,
child: Toggle(
width: isDesktop ? 490 : double.infinity,
child: Options(
key: UniqueKey(),
onText: "Extended pub key",
offText: "Single address",
onColor:
Theme.of(
context,
).extension<StackColors>()!.popupBG,
offColor:
Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
isOn: _addressOnly,
texts: [
"Single address",
"Extended pub key",
if (widget.coin is Firo)
isDesktop ? "Spark View Key" : "View Key"
],
onColor: Theme.of(context)
.extension<StackColors>()!
.popupBG,
offColor: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
selectedIndex: _walletType.index-1,
onValueChanged: (value) {
setState(() {
_addressOnly = value;
_walletType = ViewOnlyWalletType.values[value+1];
});
},
decoration: BoxDecoration(
Expand All @@ -420,8 +436,10 @@ class _RestoreViewOnlyWalletViewState
),
),
),
SizedBox(height: isDesktop ? 24 : 16),
if (!isElectrumX || _addressOnly)
SizedBox(
height: isDesktop ? 24 : 16,
),
if (!isElectrumX || _walletType == ViewOnlyWalletType.addressOnly)
FullTextField(
key: const Key("viewOnlyAddressRestoreFieldKey"),
label: "Address",
Expand All @@ -441,8 +459,11 @@ class _RestoreViewOnlyWalletViewState
}
},
),
if (!isElectrumX) SizedBox(height: isDesktop ? 16 : 12),
if (isElectrumX && !_addressOnly)
if (!isElectrumX)
SizedBox(
height: isDesktop ? 16 : 12,
),
if (isElectrumX && _walletType == ViewOnlyWalletType.xPub)
DropdownButtonHideUnderline(
child: DropdownButton2<String>(
value: _currentDropDownValue,
Expand Down Expand Up @@ -513,9 +534,11 @@ class _RestoreViewOnlyWalletViewState
),
),
),
if (isElectrumX && !_addressOnly)
SizedBox(height: isDesktop ? 16 : 12),
if (!isElectrumX || !_addressOnly)
if (isElectrumX && _walletType == ViewOnlyWalletType.xPub)
SizedBox(
height: isDesktop ? 16 : 12,
),
if (!isElectrumX || _walletType == ViewOnlyWalletType.xPub)
FullTextField(
key: const Key("viewOnlyKeyRestoreFieldKey"),
label:
Expand All @@ -536,6 +559,21 @@ class _RestoreViewOnlyWalletViewState
}
},
),
if (_walletType == ViewOnlyWalletType.spark)
SizedBox(
height: isDesktop ? 16 : 12,
),
if (_walletType == ViewOnlyWalletType.spark)
FullTextField(
key: const Key("viewOnlySparkViewKeyRestoreFieldKey"),
label: "Spark View Key",
controller: sparkViewKeyController,
onChanged: (value) {
setState(() {
_enableRestoreButton = value.isNotEmpty;
});
},
),
if (!isDesktop) const Spacer(),
SizedBox(height: isDesktop ? 24 : 16),
PrimaryButton(
Expand Down
8 changes: 4 additions & 4 deletions lib/pages/receive_view/receive_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,16 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
if (wallet is Bip39HDWallet && wallet is! BCashInterface) {
DerivePathType? type;
if (wallet.isViewOnly && wallet is ExtendedKeysInterface) {
final voData =
await wallet.getViewOnlyWalletData()
as ExtendedKeysViewOnlyWalletData;
final voData = await wallet.getViewOnlyWalletData();
for (final t in wallet.cryptoCurrency.supportedDerivationPathTypes) {
final testPath = wallet.cryptoCurrency.constructDerivePath(
derivePathType: t,
chain: 0,
index: 0,
);
if (testPath.startsWith(voData.xPubs.first.path)) {
if (voData is SparkViewOnlyWalletData) {
type = t;
} else if (testPath.startsWith((voData as ExtendedKeysViewOnlyWalletData).xPubs.first.path)) {
type = t;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,22 @@ class ViewOnlyWalletDataWidget extends StatelessWidget {
),
],
),
final SparkViewOnlyWalletData e => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DetailItem(
title: "View Key",
detail: e.viewKey,
button: Util.isDesktop
? IconCopyButton(
data: e.viewKey,
)
: SimpleCopyButton(
data: e.viewKey,
),
),
],
),
};
}
}
Loading
Loading