Skip to content

Commit b455bd4

Browse files
committed
Implement built-in walletd service
- Add WalletDaemonService for embedded wallet daemon management - Update FuegoRPCService to use local walletd (port 8070) instead of remote - Keep remote fuegod connection (port 18180) for blockchain data - Add walletd binaries to assets for all platforms - Update GitHub Actions workflow to download walletd binaries - Initialize WalletDaemonService on app startup - Update documentation for new binary structure This enables the app to run a local wallet daemon while maintaining connection to remote Fuego network for blockchain synchronization.
1 parent 173bf15 commit b455bd4

File tree

6 files changed

+246
-5
lines changed

6 files changed

+246
-5
lines changed

.github/workflows/xfg-wallet-desktop.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ jobs:
5454
mkdir -p assets/bin
5555
mv xfg-stark-cli-macos assets/bin/
5656
57+
- name: Download fuego-walletd
58+
run: |
59+
curl -L -o fuego-walletd-macos "https://github.com/usexfg/fuego/releases/latest/download/fuego-walletd-macos"
60+
chmod +x fuego-walletd-macos
61+
mv fuego-walletd-macos assets/bin/
62+
5763
- name: Install dependencies
5864
run: flutter pub get
5965

@@ -103,6 +109,11 @@ jobs:
103109
New-Item -ItemType Directory -Force -Path assets\bin
104110
Move-Item xfg-stark-cli-windows.exe assets\bin\xfg-stark-cli.exe
105111
112+
- name: Download fuego-walletd
113+
run: |
114+
curl -L -o fuego-walletd-windows.exe "https://github.com/usexfg/fuego/releases/latest/download/fuego-walletd-windows.exe"
115+
Move-Item fuego-walletd-windows.exe assets\bin\fuego-walletd-windows.exe
116+
106117
- name: Install dependencies
107118
run: flutter pub get
108119

assets/bin/README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@ This directory contains platform-specific CLI binaries for the XF₲ Wallet.
44

55
## Binaries
66

7+
### STARK Proof Generation
78
- `xfg-stark-cli-linux` - Linux binary for STARK proof generation
89
- `xfg-stark-cli-macos` - macOS binary for STARK proof generation
910
- `xfg-stark-cli.exe` - Windows binary for STARK proof generation
1011

12+
### Wallet Daemon
13+
- `fuego-walletd-linux` - Linux wallet daemon binary
14+
- `fuego-walletd-macos` - macOS wallet daemon binary
15+
- `fuego-walletd-windows.exe` - Windows wallet daemon binary
16+
1117
## Usage
1218

13-
These binaries are automatically downloaded during the GitHub Actions build process and bundled with the application. The CLIService handles extracting and executing the appropriate binary for the current platform.
19+
These binaries are automatically downloaded during the GitHub Actions build process and bundled with the application. The services handle extracting and executing the appropriate binary for the current platform.
1420

15-
## Source
21+
## Sources
1622

17-
Binaries are downloaded from: https://github.com/ColinRitman/xfgwin/releases/tag/v0.8.8
23+
- STARK CLI binaries: https://github.com/ColinRitman/xfgwin/releases/tag/v0.8.8
24+
- Wallet daemon binaries: https://github.com/usexfg/fuego/releases/latest

lib/main.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@ import 'package:provider/provider.dart';
33
import 'package:flutter/services.dart';
44
import 'providers/wallet_provider.dart';
55
import 'services/fuego_rpc_service.dart';
6+
import 'services/wallet_daemon_service.dart';
67
import 'screens/splash_screen.dart';
78
import 'utils/theme.dart';
89

9-
void main() {
10+
void main() async {
1011
WidgetsFlutterBinding.ensureInitialized();
1112

13+
// Initialize WalletDaemonService
14+
await WalletDaemonService.initialize(
15+
daemonAddress: '207.244.247.64',
16+
daemonPort: 18180,
17+
);
18+
1219
// Set preferred orientations
1320
SystemChrome.setPreferredOrientations([
1421
DeviceOrientation.portraitUp,

lib/services/fuego_rpc_service.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ class FuegoRPCService {
299299
Map<String, dynamic> params,
300300
) async {
301301
try {
302-
final walletUrl = _baseUrl.replaceAll(':$defaultRpcPort', ':$defaultWalletPort');
302+
// Use local walletd instead of remote
303+
final walletUrl = 'http://localhost:8070';
303304

304305
final response = await _dio.post(
305306
'$walletUrl/json_rpc',
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import 'dart:async';
2+
import 'dart:io';
3+
import 'dart:convert';
4+
import 'package:flutter/foundation.dart';
5+
import 'package:flutter/services.dart';
6+
import 'package:path_provider/path_provider.dart';
7+
import 'package:path/path.dart' as path;
8+
9+
class WalletDaemonService {
10+
static Process? _walletdProcess;
11+
static bool _isRunning = false;
12+
static int _walletdPort = 8070;
13+
static String? _walletdPath;
14+
static String? _walletPath;
15+
static String? _daemonAddress;
16+
static int? _daemonPort;
17+
18+
/// Initialize the wallet daemon service
19+
static Future<void> initialize({
20+
required String daemonAddress,
21+
required int daemonPort,
22+
String? walletPath,
23+
}) async {
24+
_daemonAddress = daemonAddress;
25+
_daemonPort = daemonPort;
26+
_walletPath = walletPath;
27+
28+
// Extract walletd binary
29+
_walletdPath = await _extractWalletdBinary();
30+
31+
debugPrint('WalletDaemonService initialized');
32+
debugPrint('Daemon: $_daemonAddress:$_daemonPort');
33+
debugPrint('Walletd binary: $_walletdPath');
34+
debugPrint('Wallet path: $_walletPath');
35+
}
36+
37+
/// Extract the walletd binary from assets
38+
static Future<String> _extractWalletdBinary() async {
39+
final Directory tempDir = await getTemporaryDirectory();
40+
final String binaryName = Platform.isWindows
41+
? 'fuego-walletd-windows.exe'
42+
: Platform.isMacOS
43+
? 'fuego-walletd-macos'
44+
: 'fuego-walletd-linux';
45+
46+
final File binaryFile = File(path.join(tempDir.path, 'fuego-walletd'));
47+
48+
// Extract from assets if not already extracted
49+
if (!await binaryFile.exists()) {
50+
await binaryFile.create(recursive: true);
51+
await binaryFile.writeAsBytes(
52+
await rootBundle.load('assets/bin/$binaryName').then((data) => data.buffer.asUint8List())
53+
);
54+
}
55+
56+
// Set executable permissions for non-Windows platforms
57+
if (!Platform.isWindows) {
58+
await Process.run('chmod', ['+x', binaryFile.path]);
59+
}
60+
61+
return binaryFile.path;
62+
}
63+
64+
/// Start the wallet daemon
65+
static Future<bool> startWalletd({
66+
String? walletPath,
67+
String? password,
68+
}) async {
69+
if (_isRunning) {
70+
debugPrint('Walletd is already running');
71+
return true;
72+
}
73+
74+
if (_walletdPath == null) {
75+
throw Exception('WalletDaemonService not initialized');
76+
}
77+
78+
try {
79+
// Prepare command arguments
80+
final List<String> args = [
81+
'--daemon-address', '$_daemonAddress',
82+
'--daemon-port', '$_daemonPort.toString()',
83+
'--rpc-bind-port', '_walletdPort.toString()',
84+
'--log-level', '1', // Info level
85+
'--non-interactive',
86+
];
87+
88+
// Add wallet path if provided
89+
if (walletPath != null) {
90+
args.addAll(['--wallet-file', walletPath]);
91+
}
92+
93+
// Add password if provided
94+
if (password != null) {
95+
args.addAll(['--password', password]);
96+
}
97+
98+
debugPrint('Starting walletd with args: $args');
99+
100+
// Start the process
101+
_walletdProcess = await Process.start(_walletdPath!, args);
102+
103+
// Listen to stdout and stderr
104+
_walletdProcess!.stdout.transform(utf8.decoder).listen((data) {
105+
debugPrint('Walletd stdout: $data');
106+
});
107+
108+
_walletdProcess!.stderr.transform(utf8.decoder).listen((data) {
109+
debugPrint('Walletd stderr: $data');
110+
});
111+
112+
// Wait a moment for startup
113+
await Future.delayed(const Duration(seconds: 2));
114+
115+
// Check if process is still running
116+
if (_walletdProcess!.exitCode == null) {
117+
_isRunning = true;
118+
debugPrint('Walletd started successfully on port $_walletdPort');
119+
return true;
120+
} else {
121+
debugPrint('Walletd failed to start');
122+
return false;
123+
}
124+
} catch (e) {
125+
debugPrint('Error starting walletd: $e');
126+
return false;
127+
}
128+
}
129+
130+
/// Stop the wallet daemon
131+
static Future<void> stopWalletd() async {
132+
if (!_isRunning || _walletdProcess == null) {
133+
return;
134+
}
135+
136+
try {
137+
_walletdProcess!.kill();
138+
await _walletdProcess!.exitCode;
139+
_walletdProcess = null;
140+
_isRunning = false;
141+
debugPrint('Walletd stopped');
142+
} catch (e) {
143+
debugPrint('Error stopping walletd: $e');
144+
}
145+
}
146+
147+
/// Check if walletd is running
148+
static bool get isRunning => _isRunning;
149+
150+
/// Get the walletd port
151+
static int get port => _walletdPort;
152+
153+
/// Get the walletd URL
154+
static String get url => 'http://localhost:$_walletdPort';
155+
156+
/// Restart walletd with new parameters
157+
static Future<bool> restartWalletd({
158+
String? walletPath,
159+
String? password,
160+
}) async {
161+
await stopWalletd();
162+
await Future.delayed(const Duration(seconds: 1));
163+
return await startWalletd(walletPath: walletPath, password: password);
164+
}
165+
166+
/// Create a new wallet
167+
static Future<bool> createWallet({
168+
required String walletPath,
169+
required String password,
170+
}) async {
171+
if (_walletdPath == null) {
172+
throw Exception('WalletDaemonService not initialized');
173+
}
174+
175+
try {
176+
final List<String> args = [
177+
'--daemon-address', '$_daemonAddress',
178+
'--daemon-port', '$_daemonPort.toString()',
179+
'--wallet-file', walletPath,
180+
'--password', password,
181+
'--generate-new-wallet',
182+
'--non-interactive',
183+
];
184+
185+
debugPrint('Creating wallet with args: $args');
186+
187+
final ProcessResult result = await Process.run(_walletdPath!, args);
188+
189+
if (result.exitCode == 0) {
190+
debugPrint('Wallet created successfully');
191+
return true;
192+
} else {
193+
debugPrint('Wallet creation failed: ${result.stderr}');
194+
return false;
195+
}
196+
} catch (e) {
197+
debugPrint('Error creating wallet: $e');
198+
return false;
199+
}
200+
}
201+
202+
/// Open an existing wallet
203+
static Future<bool> openWallet({
204+
required String walletPath,
205+
required String password,
206+
}) async {
207+
return await startWalletd(
208+
walletPath: walletPath,
209+
password: password,
210+
);
211+
}
212+
}

pubspec.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ flutter:
9191
- assets/bin/xfg-stark-cli-linux
9292
- assets/bin/xfg-stark-cli-macos
9393
- assets/bin/xfg-stark-cli-windows.exe
94+
- assets/bin/fuego-walletd-linux
95+
- assets/bin/fuego-walletd-macos
96+
- assets/bin/fuego-walletd-windows.exe
9497

9598
# An image asset can refer to one or more resolution-specific "variants", see
9699
# https://flutter.dev/assets-and-images/#resolution-aware

0 commit comments

Comments
 (0)