Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

launcher: restore starter functionality to launch with l2 #545

Merged
merged 12 commits into from
Jan 29, 2025
6 changes: 2 additions & 4 deletions clients/launcher/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,8 @@ Future<void> initDependencies(Logger log) async {
QuotesProvider(prefs),
);

// Register services
GetIt.I.registerLazySingleton<WalletService>(
() => WalletService(),
);
// Register wallet service
GetIt.I.registerSingleton<WalletService>(WalletService());
}

Future<List<Binary>> _loadBinaries(Directory appDir) async {
Expand Down
2 changes: 0 additions & 2 deletions clients/launcher/lib/pages/overview_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class _OverviewPageState extends State<OverviewPage> {
WidgetsBinding.instance.addPostFrameCallback((_) {
_binaryProvider.addListener(_onBinaryProviderUpdate);
_processProvider.addListener(_onBinaryProviderUpdate);
_walletService.addListener(_onBinaryProviderUpdate);
_blockchainProvider.addListener(_onBinaryProviderUpdate);
});
}
Expand All @@ -57,7 +56,6 @@ class _OverviewPageState extends State<OverviewPage> {
void dispose() {
_binaryProvider.removeListener(_onBinaryProviderUpdate);
_processProvider.removeListener(_onBinaryProviderUpdate);
_walletService.removeListener(_onBinaryProviderUpdate);
_blockchainProvider.removeListener(_onBinaryProviderUpdate);
super.dispose();
}
Expand Down
2 changes: 1 addition & 1 deletion clients/launcher/lib/services/wallet_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,4 @@ class WalletService extends ChangeNotifier {
_logger.e('Error generating starters for downloaded chains: $e\n$stack');
}
}
}
}
81 changes: 35 additions & 46 deletions clients/launcher/lib/widgets/welcome_modal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,14 @@ class _WelcomeModalContentState extends State<_WelcomeModalContent> {
}

final words = _currentWalletData['mnemonic'].split(' ');
final binaryStrings = _currentWalletData['binary_strings'] as List<String>;
final binaryString = _currentWalletData['bip39_binary'] ?? '';
final binaryStrings = <String>[];

// Split binary string into 11-bit chunks
for (int i = 0; i < binaryString.length; i += 11) {
final end = i + 11 > binaryString.length ? binaryString.length : i + 11;
binaryStrings.add(binaryString.substring(i, end).padRight(11, '0'));
}

return SailRawCard(
padding: true,
Expand All @@ -396,24 +403,10 @@ class _WelcomeModalContentState extends State<_WelcomeModalContent> {
children: [
SailText.primary10(words[row * 6 + col], bold: true),
if (row * 6 + col < binaryStrings.length)
row * 6 + col == words.length - 1
? Row(
mainAxisSize: MainAxisSize.min,
children: [
SailText.primary10(
binaryStrings[row * 6 + col].substring(0, 7),
color: SailTheme.of(context).colors.textSecondary,
),
SailText.primary10(
binaryStrings[row * 6 + col].substring(7),
color: SailTheme.of(context).colors.success,
),
],
)
: SailText.primary10(
binaryStrings[row * 6 + col],
color: SailTheme.of(context).colors.textSecondary,
),
SailText.primary10(
binaryStrings[row * 6 + col],
color: SailTheme.of(context).colors.textSecondary,
),
],
),
),
Expand All @@ -430,7 +423,6 @@ class _WelcomeModalContentState extends State<_WelcomeModalContent> {

Widget _buildInfoPanel() {
final theme = SailTheme.of(context);
final binaryString = _currentWalletData['bip39_binary'] as String?;

return SailRawCard(
padding: true,
Expand All @@ -449,12 +441,34 @@ class _WelcomeModalContentState extends State<_WelcomeModalContent> {
),
Expanded(
child: SailText.primary10(
binaryString ?? '',
_currentWalletData['bip39_binary'] ?? '',
color: theme.colors.textSecondary,
),
),
],
),
// BIP39 Checksum
SailRow(
spacing: SailStyleValues.padding08,
children: [
SizedBox(
width: 100,
child: SailText.primary10('Checksum:', bold: true),
),
SailText.primary10(
_currentWalletData['bip39_checksum'] ?? '',
color: theme.colors.textSecondary,
),
const SizedBox(width: SailStyleValues.padding16),
SailText.primary10('Hex:', bold: true),
const SizedBox(width: SailStyleValues.padding04),
SailText.primary10(
_currentWalletData['bip39_checksum_hex'] ?? '',
color: theme.colors.textSecondary,
),
Expanded(child: Container()),
],
),
// Master Key
SailRow(
spacing: SailStyleValues.padding08,
Expand Down Expand Up @@ -707,31 +721,6 @@ class _WelcomeModalContentState extends State<_WelcomeModalContent> {
return;
}

// Process binary representation
final binaryString = wallet['bip39_binary'] as String;
final words = (wallet['mnemonic'] as String).split(' ');
final binaryStrings = <String>[];

// For 12 words: 11 words × 11 bits + 7 bits + 4 checksum bits = 132 bits
final checksumBits = wallet['bip39_checksum'] as String;
final entropyBits = binaryString.substring(0, binaryString.length - checksumBits.length);

// Split into 11-bit chunks for each word
for (int i = 0; i < words.length - 1; i++) {
final start = i * 11;
final end = start + 11;
final chunk = entropyBits.substring(start, end);
binaryStrings.add(chunk);
}

// Handle last word specially (7 bits entropy + 4 bits checksum)
final lastEntropyBits = entropyBits.substring(entropyBits.length - 7);
final lastWord = lastEntropyBits + checksumBits;
binaryStrings.add(lastWord);

// Update wallet data with processed binary strings
wallet['binary_strings'] = binaryStrings;

setState(() {
_currentWalletData = Map<String, dynamic>.from(wallet);
_isValidInput = true;
Expand Down
2 changes: 1 addition & 1 deletion clients/launcher/test/test_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Future<void> registerTestDependencies() async {

if (!GetIt.I.isRegistered<WalletService>()) {
GetIt.I.registerLazySingleton<WalletService>(
() => WalletService(),
() => WalletService(GetIt.I.get<BinaryProvider>()),
);
}
}
9 changes: 9 additions & 0 deletions clients/sail_ui/lib/classes/rpc_connection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,16 @@ abstract class RPCConnection extends ChangeNotifier {
Future<void> initBinary(
BuildContext context, {
List<String>? arg,
String? mnemonicPath,
}) async {
if (mnemonicPath != null && binary is Sidechain) {
final sidechain = binary as Sidechain;
// Only set the mnemonic path if it's not already set
if (sidechain.mnemonicSeedPhrasePath == null) {
sidechain.mnemonicSeedPhrasePath = mnemonicPath;
}
}

mplatt8 marked this conversation as resolved.
Show resolved Hide resolved
final args = await binaryArgs(conf);
args.addAll(arg ?? []);

Expand Down
89 changes: 72 additions & 17 deletions clients/sail_ui/lib/providers/binary_provider.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
Expand All @@ -12,7 +13,6 @@ import 'package:sail_ui/rpcs/bitwindow_api.dart';
import 'package:sail_ui/rpcs/enforcer_rpc.dart';
import 'package:sail_ui/rpcs/mainchain_rpc.dart';
import 'package:sail_ui/rpcs/thunder_rpc.dart';

/// Represents the current status of a binary download
class DownloadState {
final double progress; // Only used during installing
Expand Down Expand Up @@ -168,6 +168,14 @@ class BinaryProvider extends ChangeNotifier {
Future<void> startBinary(BuildContext context, Binary binary, {bool useStarter = false}) async {
if (!context.mounted) return;

if (useStarter && (binary is Thunder || binary is Bitnames)) {
try {
await _setStarterSeed(binary);
} catch (e) {
log.e('Error setting starter seed: $e');
}
}

switch (binary) {
case ParentChain():
await mainchainRPC.initBinary(context);
Expand All @@ -179,24 +187,20 @@ class BinaryProvider extends ChangeNotifier {
await bitwindowRPC.initBinary(context);

case Thunder():
await thunderRPC.initBinary(context);
if (useStarter) {
try {
await _setStarterSeed(binary);
} catch (e) {
log.e('Error setting starter seed: $e');
}
}
await thunderRPC.initBinary(
context,
arg: binary.mnemonicSeedPhrasePath != null
? ['--mnemonic-seed-phrase-path', binary.mnemonicSeedPhrasePath!]
: null,
);

case Bitnames():
await bitnamesRPC.initBinary(context);
if (useStarter) {
try {
await _setStarterSeed(binary);
} catch (e) {
log.e('Error setting starter seed: $e');
}
}
await bitnamesRPC.initBinary(
context,
arg: binary.mnemonicSeedPhrasePath != null
? ['--mnemonic-seed-phrase-path', binary.mnemonicSeedPhrasePath!]
: null,
);

default:
log.i('is $binary');
Expand Down Expand Up @@ -282,10 +286,57 @@ class BinaryProvider extends ChangeNotifier {
};
}

Future<bool> _isSidechainInitialized(int slot) async {
try {
final masterStarterPath = path.join(appDir.path, 'wallet_starters', 'master_starter.json');
final masterStarterFile = File(masterStarterPath);

if (!masterStarterFile.existsSync()) {
return false;
}

final masterData = jsonDecode(await masterStarterFile.readAsString()) as Map<String, dynamic>;
return masterData['sidechain_${slot}_init'] ?? false;
} catch (e) {
log.e('Error checking sidechain initialization: $e');
return false;
}
}

Future<void> _setSidechainInitialized(int slot) async {
try {
final masterStarterPath = path.join(appDir.path, 'wallet_starters', 'master_starter.json');
final masterStarterFile = File(masterStarterPath);

if (!masterStarterFile.existsSync()) {
return;
}

final masterData = jsonDecode(await masterStarterFile.readAsString()) as Map<String, dynamic>;
masterData['sidechain_${slot}_init'] = true;
await masterStarterFile.writeAsString(jsonEncode(masterData));
} catch (e) {
log.e('Error setting sidechain initialization: $e');
}
}

Future<void> _setStarterSeed(Binary binary) async {
if (binary is! Sidechain) return;

try {
// Check if this sidechain has already been initialized
final isInitialized = await _isSidechainInitialized(binary.slot);
if (isInitialized) {
log.i('Sidechain ${binary.name} already initialized, skipping seed setup');
return;
}

// Skip if mnemonic path is already set
if (binary.mnemonicSeedPhrasePath != null) {
log.i('Sidechain ${binary.name} already has mnemonic path set, skipping seed setup');
return;
}

final starterDir = path.join(appDir.path, 'wallet_starters');
final starterFile = File(
path.join(
Expand All @@ -302,6 +353,10 @@ class BinaryProvider extends ChangeNotifier {
log.i('Found starter file, setting mnemonic seed phrase path');
binary.mnemonicSeedPhrasePath = starterFile.path;
log.i('Successfully set mnemonic seed phrase path to: ${starterFile.path}');

// Mark this sidechain as initialized
await _setSidechainInitialized(binary.slot);
notifyListeners();
} catch (e, st) {
log.e('Error setting starter seed', error: e, stackTrace: st);
rethrow;
Expand Down
10 changes: 10 additions & 0 deletions clients/sidesail/lib/rpc/rpc_ethereum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:sail_ui/sail_ui.dart';
import 'package:sidesail/rpc/rpc_sidechain.dart';
import 'package:web3dart/json_rpc.dart' as jsonrpc;
import 'package:web3dart/web3dart.dart';
import 'package:flutter/material.dart';

abstract class EthereumRPC extends SidechainRPC {
EthereumRPC({
Expand Down Expand Up @@ -194,6 +195,15 @@ class EthereumRPCLive extends EthereumRPC {
warnings: [],
);
}

@override
Future<void> initBinary(
BuildContext context, {
List<String>? arg,
String? mnemonicPath,
}) async {
await super.initBinary(context, arg: arg, mnemonicPath: mnemonicPath);
}
}

/// List of all known RPC methods available /
Expand Down
10 changes: 10 additions & 0 deletions clients/sidesail/lib/rpc/rpc_testchain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:sidesail/rpc/models/bmm_result.dart';
import 'package:sidesail/rpc/models/bundle_info.dart';
import 'package:sidesail/rpc/rpc_sidechain.dart';
import 'package:sidesail/rpc/rpc_withdrawal_bundle.dart';
import 'package:flutter/material.dart';

/// RPC connection the sidechain node.
abstract class TestchainRPC extends SidechainRPC {
Expand Down Expand Up @@ -272,6 +273,15 @@ class TestchainRPCLive extends TestchainRPC {
final confirmedFut = await _client().call('getblockchaininfo');
return BlockchainInfo.fromMap(confirmedFut);
}

@override
Future<void> initBinary(
BuildContext context, {
List<String>? arg,
String? mnemonicPath,
}) async {
await super.initBinary(context, arg: arg, mnemonicPath: mnemonicPath);
}
mplatt8 marked this conversation as resolved.
Show resolved Hide resolved
}

class TestchainRPCError {
Expand Down
1 change: 1 addition & 0 deletions clients/sidesail/lib/rpc/rpc_zcash.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ abstract class ZCashRPC extends SidechainRPC {
Future<void> initBinary(
BuildContext context, {
List<String>? arg,
String? mnemonicPath,
}) async {
final args = await binaryArgs(conf);
args.addAll(arg ?? []);
Expand Down
Loading