@waiaas/daemon 2.12.0-rc → 2.12.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/middleware/request-logger.d.ts +4 -1
- package/dist/api/middleware/request-logger.d.ts.map +1 -1
- package/dist/api/middleware/request-logger.js +20 -10
- package/dist/api/middleware/request-logger.js.map +1 -1
- package/dist/api/routes/actions.d.ts.map +1 -1
- package/dist/api/routes/actions.js +14 -5
- package/dist/api/routes/actions.js.map +1 -1
- package/dist/api/routes/admin-actions.d.ts.map +1 -1
- package/dist/api/routes/admin-actions.js +6 -1
- package/dist/api/routes/admin-actions.js.map +1 -1
- package/dist/infrastructure/settings/hot-reload.d.ts +3 -0
- package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -1
- package/dist/infrastructure/settings/hot-reload.js +11 -0
- package/dist/infrastructure/settings/hot-reload.js.map +1 -1
- package/dist/lifecycle/daemon-shutdown.d.ts.map +1 -1
- package/dist/lifecycle/daemon-shutdown.js +9 -8
- package/dist/lifecycle/daemon-shutdown.js.map +1 -1
- package/dist/lifecycle/daemon-startup.d.ts.map +1 -1
- package/dist/lifecycle/daemon-startup.js +96 -66
- package/dist/lifecycle/daemon-startup.js.map +1 -1
- package/dist/lifecycle/daemon.d.ts +3 -1
- package/dist/lifecycle/daemon.d.ts.map +1 -1
- package/dist/lifecycle/daemon.js +2 -1
- package/dist/lifecycle/daemon.js.map +1 -1
- package/package.json +5 -5
- package/public/admin/assets/index-CgCvTM98.js +3 -0
- package/public/admin/index.html +1 -1
- package/public/admin/assets/index-CpFF2lCo.js +0 -3
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
10
10
|
import { createRequire } from 'node:module';
|
|
11
11
|
import { join, dirname } from 'node:path';
|
|
12
|
-
import { WAIaaSError, BUILT_IN_RPC_DEFAULTS, RpcPool, safeJsonParse } from '@waiaas/core';
|
|
12
|
+
import { WAIaaSError, BUILT_IN_RPC_DEFAULTS, RpcPool, safeJsonParse, ConsoleLogger } from '@waiaas/core';
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
import { KillSwitchService } from '../services/kill-switch-service.js';
|
|
15
15
|
import { AutoStopService } from '../services/autostop-service.js';
|
|
@@ -48,7 +48,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
48
48
|
state._config = loadConfig(dataDir);
|
|
49
49
|
// Acquire daemon lock (flock-like via proper-lockfile)
|
|
50
50
|
await state.acquireDaemonLock(dataDir);
|
|
51
|
-
|
|
51
|
+
// Initialize daemon logger with config log_level (default: 'info')
|
|
52
|
+
const configLogLevel = (state._config.daemon.log_level ?? 'info');
|
|
53
|
+
state.logger = new ConsoleLogger('daemon', configLogLevel);
|
|
54
|
+
state.logger.debug('Step 1: Config loaded, daemon lock acquired');
|
|
52
55
|
})(), 5_000, 'STEP1_CONFIG_LOCK');
|
|
53
56
|
// ------------------------------------------------------------------
|
|
54
57
|
// Step 2: Database initialization (30s, fail-fast)
|
|
@@ -72,7 +75,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
72
75
|
});
|
|
73
76
|
}
|
|
74
77
|
if (compatibility.action === 'migrate') {
|
|
75
|
-
|
|
78
|
+
state.logger.debug('Step 2: Schema migration needed, applying...');
|
|
76
79
|
}
|
|
77
80
|
// Create all tables + run migrations (idempotent)
|
|
78
81
|
pushSchema(sqlite);
|
|
@@ -86,9 +89,9 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
86
89
|
});
|
|
87
90
|
const importResult = state._settingsService.importFromConfig();
|
|
88
91
|
if (importResult.imported > 0) {
|
|
89
|
-
|
|
92
|
+
state.logger.debug(`Step 2: Settings imported from config.toml (${importResult.imported} keys)`);
|
|
90
93
|
}
|
|
91
|
-
|
|
94
|
+
state.logger.debug('Step 2: Database initialized');
|
|
92
95
|
})(), 30_000, 'STEP2_DATABASE');
|
|
93
96
|
// ------------------------------------------------------------------
|
|
94
97
|
// Step 2b: Master password validation (fail-fast)
|
|
@@ -106,7 +109,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
106
109
|
console.error('Invalid master password.');
|
|
107
110
|
process.exit(1);
|
|
108
111
|
}
|
|
109
|
-
|
|
112
|
+
state.logger.debug('Step 2b: Master password verified (DB hash)');
|
|
110
113
|
}
|
|
111
114
|
else {
|
|
112
115
|
// Path B: No DB hash -> check for existing keystore files
|
|
@@ -153,10 +156,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
153
156
|
console.error('Invalid master password. Cannot decrypt existing wallets.');
|
|
154
157
|
process.exit(1);
|
|
155
158
|
}
|
|
156
|
-
|
|
159
|
+
state.logger.debug('Step 2b: Master password verified (keystore migration)');
|
|
157
160
|
}
|
|
158
161
|
else {
|
|
159
|
-
|
|
162
|
+
state.logger.debug('Step 2b: First install, no password validation needed');
|
|
160
163
|
}
|
|
161
164
|
// Store hash in DB for future startups
|
|
162
165
|
const hash = await argon2.hash(masterPassword, {
|
|
@@ -190,10 +193,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
190
193
|
// v1.1: just verify keystore infrastructure is accessible
|
|
191
194
|
// Full key decryption happens when agents are accessed
|
|
192
195
|
if (masterPassword) {
|
|
193
|
-
|
|
196
|
+
state.logger.debug('Step 3: Keystore infrastructure verified (master password provided)');
|
|
194
197
|
}
|
|
195
198
|
else {
|
|
196
|
-
|
|
199
|
+
state.logger.debug('Step 3: Keystore infrastructure verified (no master password)');
|
|
197
200
|
}
|
|
198
201
|
})(), 30_000, 'STEP3_KEYSTORE');
|
|
199
202
|
// ------------------------------------------------------------------
|
|
@@ -229,13 +232,33 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
229
232
|
state.rpcPool.register(network, [url]);
|
|
230
233
|
}
|
|
231
234
|
}
|
|
232
|
-
// 3.
|
|
235
|
+
// 3. Seed Admin Settings rpc_pool.* URLs (higher priority than built-in defaults)
|
|
236
|
+
if (state._settingsService) {
|
|
237
|
+
const { SETTING_DEFINITIONS } = await import('../infrastructure/settings/setting-keys.js');
|
|
238
|
+
const rpcPoolKeys = SETTING_DEFINITIONS
|
|
239
|
+
.filter(d => d.category === 'rpc_pool')
|
|
240
|
+
.map(d => d.key);
|
|
241
|
+
for (const settingKey of rpcPoolKeys) {
|
|
242
|
+
const raw = state._settingsService.get(settingKey);
|
|
243
|
+
if (!raw || raw === '[]')
|
|
244
|
+
continue;
|
|
245
|
+
try {
|
|
246
|
+
const parsed = JSON.parse(raw);
|
|
247
|
+
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
248
|
+
continue;
|
|
249
|
+
const network = settingKey.replace('rpc_pool.', '');
|
|
250
|
+
state.rpcPool.register(network, parsed);
|
|
251
|
+
}
|
|
252
|
+
catch { /* skip invalid JSON */ }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// 4. Register built-in defaults (lower priority, appended after config + admin URLs)
|
|
233
256
|
for (const [network, urls] of Object.entries(BUILT_IN_RPC_DEFAULTS)) {
|
|
234
257
|
state.rpcPool.register(network, [...urls]);
|
|
235
258
|
}
|
|
236
|
-
//
|
|
259
|
+
// 5. Create AdapterPool with RpcPool
|
|
237
260
|
state.adapterPool = new AdapterPool(state.rpcPool);
|
|
238
|
-
|
|
261
|
+
state.logger.debug(`Step 4: AdapterPool created with RpcPool (${state.rpcPool.getNetworks().length} networks seeded)`);
|
|
239
262
|
})(), 10_000, 'STEP4_ADAPTER');
|
|
240
263
|
}
|
|
241
264
|
catch (err) {
|
|
@@ -257,7 +280,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
257
280
|
},
|
|
258
281
|
onApproved: (txId) => state.handleApprovalApproved(txId),
|
|
259
282
|
});
|
|
260
|
-
|
|
283
|
+
state.logger.debug('Step 4b: Workflow instances created (DelayQueue + ApprovalWorkflow)');
|
|
261
284
|
}
|
|
262
285
|
// ------------------------------------------------------------------
|
|
263
286
|
// Step 4c: JWT Secret Manager + master password hash
|
|
@@ -273,7 +296,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
273
296
|
});
|
|
274
297
|
// Create mutable ref for live password/hash updates (password change API)
|
|
275
298
|
state.passwordRef = { password: masterPassword, hash: state.masterPasswordHash };
|
|
276
|
-
|
|
299
|
+
state.logger.debug('Step 4c: JWT secret manager initialized, master password hashed');
|
|
277
300
|
}
|
|
278
301
|
// ------------------------------------------------------------------
|
|
279
302
|
// Step 4c-2: KillSwitchService initialization
|
|
@@ -285,7 +308,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
285
308
|
eventBus: state.eventBus,
|
|
286
309
|
});
|
|
287
310
|
state.killSwitchService.ensureInitialized();
|
|
288
|
-
|
|
311
|
+
state.logger.debug('Step 4c-2: KillSwitchService initialized');
|
|
289
312
|
}
|
|
290
313
|
// ------------------------------------------------------------------
|
|
291
314
|
// Step 4d: Notification Service initialization (fail-soft)
|
|
@@ -353,7 +376,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
353
376
|
}
|
|
354
377
|
}
|
|
355
378
|
const channelNames = state.notificationService.getChannelNames();
|
|
356
|
-
|
|
379
|
+
state.logger.debug(`Step 4d: NotificationService initialized (${channelNames.length} channels: ${channelNames.join(', ') || 'none'})`);
|
|
357
380
|
}
|
|
358
381
|
catch (err) {
|
|
359
382
|
console.warn('Step 4d (fail-soft): NotificationService init warning:', err);
|
|
@@ -391,10 +414,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
391
414
|
});
|
|
392
415
|
if (autoStopConfig.enabled) {
|
|
393
416
|
state.autoStopService.start();
|
|
394
|
-
|
|
417
|
+
state.logger.debug('Step 4c-3: AutoStop engine started');
|
|
395
418
|
}
|
|
396
419
|
else {
|
|
397
|
-
|
|
420
|
+
state.logger.debug('Step 4c-3: AutoStop engine disabled');
|
|
398
421
|
}
|
|
399
422
|
}
|
|
400
423
|
}
|
|
@@ -421,7 +444,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
421
444
|
version: daemonVersion,
|
|
422
445
|
dataDir,
|
|
423
446
|
});
|
|
424
|
-
|
|
447
|
+
state.logger.debug('Step 4c-3b: AdminStatsService created');
|
|
425
448
|
}
|
|
426
449
|
}
|
|
427
450
|
catch (err) {
|
|
@@ -450,10 +473,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
450
473
|
});
|
|
451
474
|
if (monitorConfig.enabled) {
|
|
452
475
|
state.balanceMonitorService.start();
|
|
453
|
-
|
|
476
|
+
state.logger.debug('Step 4c-4: Balance monitor started');
|
|
454
477
|
}
|
|
455
478
|
else {
|
|
456
|
-
|
|
479
|
+
state.logger.debug('Step 4c-4: Balance monitor disabled');
|
|
457
480
|
}
|
|
458
481
|
}
|
|
459
482
|
}
|
|
@@ -488,10 +511,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
488
511
|
});
|
|
489
512
|
state.telegramBotService.start();
|
|
490
513
|
state.telegramBotRef.current = state.telegramBotService;
|
|
491
|
-
|
|
514
|
+
state.logger.debug('Step 4c-5: Telegram Bot started');
|
|
492
515
|
}
|
|
493
516
|
else {
|
|
494
|
-
|
|
517
|
+
state.logger.debug('Step 4c-5: Telegram Bot disabled');
|
|
495
518
|
}
|
|
496
519
|
}
|
|
497
520
|
catch (err) {
|
|
@@ -512,10 +535,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
512
535
|
});
|
|
513
536
|
await state.wcSessionService.initialize();
|
|
514
537
|
state.wcServiceRef.current = state.wcSessionService;
|
|
515
|
-
|
|
538
|
+
state.logger.debug('Step 4c-6: WalletConnect service initialized');
|
|
516
539
|
}
|
|
517
540
|
else {
|
|
518
|
-
|
|
541
|
+
state.logger.debug('Step 4c-6: WalletConnect disabled (no project_id)');
|
|
519
542
|
}
|
|
520
543
|
}
|
|
521
544
|
catch (err) {
|
|
@@ -536,7 +559,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
536
559
|
notificationService: state.notificationService ?? undefined,
|
|
537
560
|
eventBus: state.eventBus,
|
|
538
561
|
});
|
|
539
|
-
|
|
562
|
+
state.logger.debug('Step 4c-7: WcSigningBridge initialized');
|
|
540
563
|
}
|
|
541
564
|
}
|
|
542
565
|
catch (err) {
|
|
@@ -588,7 +611,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
588
611
|
// Inject signResponseHandler into TelegramBotService for /sign_response command (GAP-2: CHAN-04)
|
|
589
612
|
if (state.telegramBotService) {
|
|
590
613
|
state.telegramBotService.setSignResponseHandler(signResponseHandler);
|
|
591
|
-
|
|
614
|
+
state.logger.debug('Step 4c-8: signResponseHandler injected into TelegramBotService');
|
|
592
615
|
}
|
|
593
616
|
// Wallet Notification Side Channel (v2.7)
|
|
594
617
|
const walletNotifChannel = new WalletNotificationChannel({
|
|
@@ -596,11 +619,11 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
596
619
|
settingsService: state._settingsService,
|
|
597
620
|
});
|
|
598
621
|
state.notificationService?.setWalletNotificationChannel(walletNotifChannel);
|
|
599
|
-
|
|
600
|
-
|
|
622
|
+
state.logger.debug('Step 4c-8: WalletNotificationChannel injected into NotificationService');
|
|
623
|
+
state.logger.debug('Step 4c-8: Signing SDK initialized (ApprovalChannelRouter + channels)');
|
|
601
624
|
}
|
|
602
625
|
else {
|
|
603
|
-
|
|
626
|
+
state.logger.debug('Step 4c-8: Signing SDK disabled');
|
|
604
627
|
}
|
|
605
628
|
}
|
|
606
629
|
catch (err) {
|
|
@@ -718,10 +741,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
718
741
|
config: monitorConfig,
|
|
719
742
|
});
|
|
720
743
|
await state.incomingTxMonitorService.start();
|
|
721
|
-
|
|
744
|
+
state.logger.debug('Step 4c-9: Incoming TX monitor started');
|
|
722
745
|
}
|
|
723
746
|
else {
|
|
724
|
-
|
|
747
|
+
state.logger.debug('Step 4c-9: Incoming TX monitor disabled');
|
|
725
748
|
}
|
|
726
749
|
}
|
|
727
750
|
}
|
|
@@ -756,7 +779,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
756
779
|
void state.executeFromStage4(txId, walletId);
|
|
757
780
|
},
|
|
758
781
|
});
|
|
759
|
-
|
|
782
|
+
state.logger.debug('Step 4c-10: AsyncPollingService initialized (with callbacks)');
|
|
760
783
|
}
|
|
761
784
|
}
|
|
762
785
|
catch (err) {
|
|
@@ -777,10 +800,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
777
800
|
rpcPool: state.rpcPool ?? undefined,
|
|
778
801
|
});
|
|
779
802
|
state.positionTracker.start();
|
|
780
|
-
|
|
803
|
+
state.logger.debug('Step 4c-10.5: Position tracker started');
|
|
781
804
|
}
|
|
782
805
|
else {
|
|
783
|
-
|
|
806
|
+
state.logger.debug('Step 4c-10.5: Position tracker disabled');
|
|
784
807
|
}
|
|
785
808
|
}
|
|
786
809
|
}
|
|
@@ -832,7 +855,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
832
855
|
state.defiMonitorService.register(marginMonitor);
|
|
833
856
|
}
|
|
834
857
|
state.defiMonitorService.start();
|
|
835
|
-
|
|
858
|
+
state.logger.debug(`Step 4c-11: DeFi monitor service started with ${state.defiMonitorService.monitorCount} monitors`);
|
|
836
859
|
}
|
|
837
860
|
catch (err) {
|
|
838
861
|
console.warn('Step 4c-11 (fail-soft): DeFi monitor service init warning:', err);
|
|
@@ -857,7 +880,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
857
880
|
cache: priceCache,
|
|
858
881
|
crossValidationThreshold,
|
|
859
882
|
});
|
|
860
|
-
|
|
883
|
+
state.logger.debug(`Step 4e: PriceOracle initialized (Pyth primary${coingeckoOracle ? ' + CoinGecko fallback' : ''})`);
|
|
861
884
|
}
|
|
862
885
|
catch (err) {
|
|
863
886
|
console.warn('Step 4e (fail-soft): PriceOracle init warning:', err);
|
|
@@ -874,7 +897,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
874
897
|
const coingeckoApiKey = state._settingsService?.get('oracle.coingecko_api_key') ?? '';
|
|
875
898
|
const forexProvider = new CoinGeckoForexProvider(coingeckoApiKey);
|
|
876
899
|
state.forexRateService = new ForexRateService({ forexProvider, cache: forexCache });
|
|
877
|
-
|
|
900
|
+
state.logger.debug('Step 4e-2: ForexRateService initialized (30min cache)');
|
|
878
901
|
}
|
|
879
902
|
catch (err) {
|
|
880
903
|
console.warn('Step 4e-2 (fail-soft): ForexRateService init warning:', err);
|
|
@@ -923,9 +946,15 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
923
946
|
state.rpcCaller = rpcCaller;
|
|
924
947
|
// Register built-in action providers from @waiaas/actions (reads from SettingsService)
|
|
925
948
|
const { registerBuiltInProviders } = await import('@waiaas/actions');
|
|
926
|
-
const
|
|
927
|
-
const
|
|
928
|
-
const
|
|
949
|
+
const actionDebugEnv = process.env.WAIAAS_ACTION_DEBUG === 'true';
|
|
950
|
+
const actionLogLevel = actionDebugEnv ? 'debug' : state.logger.level;
|
|
951
|
+
const actionLogger = new ConsoleLogger('actions', actionLogLevel);
|
|
952
|
+
// #419/#420: Pass RPC URL resolver + failure reporter so Kamino/Drift use pool rotation on 429
|
|
953
|
+
const rpcPool = state.rpcPool;
|
|
954
|
+
const sSvc = state._settingsService;
|
|
955
|
+
const solanaRpcResolver = () => resolveRpcUrlFromPool(rpcPool, sSvc.get.bind(sSvc), 'solana', 'solana-mainnet');
|
|
956
|
+
const reportSolanaRpcFailure = (url) => rpcPool?.reportFailure('solana-mainnet', url);
|
|
957
|
+
const builtIn = registerBuiltInProviders(state.actionProviderRegistry, sSvc, { rpcCaller, logger: actionLogger, solanaRpcResolver, reportSolanaRpcFailure });
|
|
929
958
|
// Capture HyperliquidMarketData for HTTP routes (Phase 349)
|
|
930
959
|
if (builtIn.hyperliquidMarketData) {
|
|
931
960
|
state.hyperliquidMarketData = builtIn.hyperliquidMarketData;
|
|
@@ -980,7 +1009,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
980
1009
|
state.actionProviderRegistry.register(pmInfra.orderProvider);
|
|
981
1010
|
state.actionProviderRegistry.register(pmInfra.ctfProvider);
|
|
982
1011
|
state.polymarketInfra = pmInfra;
|
|
983
|
-
|
|
1012
|
+
state.logger.debug('Step 4f-pm: Polymarket providers registered (order + ctf)');
|
|
984
1013
|
}
|
|
985
1014
|
catch (err) {
|
|
986
1015
|
console.warn('Step 4f-pm (fail-soft): Polymarket registration failed:', err);
|
|
@@ -990,10 +1019,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
990
1019
|
const actionsDir = join(dataDir, 'actions');
|
|
991
1020
|
if (existsSync(actionsDir)) {
|
|
992
1021
|
const result = await state.actionProviderRegistry.loadPlugins(actionsDir);
|
|
993
|
-
|
|
1022
|
+
state.logger.debug(`Step 4f: ActionProviderRegistry initialized (${builtIn.loaded.length} built-in, ${result.loaded.length} plugins loaded, ${result.failed.length} failed)`);
|
|
994
1023
|
}
|
|
995
1024
|
else {
|
|
996
|
-
|
|
1025
|
+
state.logger.debug(`Step 4f: ActionProviderRegistry initialized (${builtIn.loaded.length} built-in, no plugins directory)`);
|
|
997
1026
|
}
|
|
998
1027
|
}
|
|
999
1028
|
catch (err) {
|
|
@@ -1015,7 +1044,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1015
1044
|
};
|
|
1016
1045
|
state._asyncPollingService.registerTracker(new BridgeStatusTracker(lifiConfig));
|
|
1017
1046
|
state._asyncPollingService.registerTracker(new BridgeMonitoringTracker(lifiConfig));
|
|
1018
|
-
|
|
1047
|
+
state.logger.debug('Step 4f-2: Bridge status trackers registered (bridge + bridge-monitoring)');
|
|
1019
1048
|
}
|
|
1020
1049
|
catch (err) {
|
|
1021
1050
|
console.warn('Step 4f-2 (fail-soft): Bridge tracker registration failed:', err);
|
|
@@ -1038,7 +1067,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1038
1067
|
};
|
|
1039
1068
|
state._asyncPollingService.registerTracker(new AcrossBridgeStatusTracker(acrossConfig));
|
|
1040
1069
|
state._asyncPollingService.registerTracker(new AcrossBridgeMonitoringTracker(acrossConfig));
|
|
1041
|
-
|
|
1070
|
+
state.logger.debug('Step 4f-2a: Across bridge status trackers registered (across-bridge + across-bridge-monitoring)');
|
|
1042
1071
|
}
|
|
1043
1072
|
catch (err) {
|
|
1044
1073
|
console.warn('Step 4f-2a (fail-soft): Across bridge tracker registration failed:', err);
|
|
@@ -1052,12 +1081,12 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1052
1081
|
if (state._settingsService?.get('actions.lido_staking_enabled') === 'true') {
|
|
1053
1082
|
const { LidoWithdrawalTracker } = await import('@waiaas/actions');
|
|
1054
1083
|
state._asyncPollingService.registerTracker(new LidoWithdrawalTracker());
|
|
1055
|
-
|
|
1084
|
+
state.logger.debug('Step 4f-3: Lido withdrawal tracker registered');
|
|
1056
1085
|
}
|
|
1057
1086
|
if (state._settingsService?.get('actions.jito_staking_enabled') === 'true') {
|
|
1058
1087
|
const { JitoEpochTracker } = await import('@waiaas/actions');
|
|
1059
1088
|
state._asyncPollingService.registerTracker(new JitoEpochTracker());
|
|
1060
|
-
|
|
1089
|
+
state.logger.debug('Step 4f-3: Jito epoch tracker registered');
|
|
1061
1090
|
}
|
|
1062
1091
|
}
|
|
1063
1092
|
catch (err) {
|
|
@@ -1073,10 +1102,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1073
1102
|
if (gasConditionEnabled) {
|
|
1074
1103
|
const { GasConditionTracker } = await import('../pipeline/gas-condition-tracker.js');
|
|
1075
1104
|
state._asyncPollingService.registerTracker(new GasConditionTracker());
|
|
1076
|
-
|
|
1105
|
+
state.logger.debug('Step 4f-4: GasConditionTracker registered');
|
|
1077
1106
|
}
|
|
1078
1107
|
else {
|
|
1079
|
-
|
|
1108
|
+
state.logger.debug('Step 4f-4: GasConditionTracker disabled');
|
|
1080
1109
|
}
|
|
1081
1110
|
}
|
|
1082
1111
|
catch (err) {
|
|
@@ -1093,10 +1122,10 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1093
1122
|
const provider = state.actionProviderRegistry.getProvider(meta.name);
|
|
1094
1123
|
if (provider && 'getPositions' in provider && 'getSupportedCategories' in provider && 'getProviderName' in provider) {
|
|
1095
1124
|
state.positionTracker.registerProvider(provider);
|
|
1096
|
-
|
|
1125
|
+
state.logger.debug(`Step 4f-5: Registered ${meta.name} with PositionTracker`);
|
|
1097
1126
|
}
|
|
1098
1127
|
}
|
|
1099
|
-
|
|
1128
|
+
state.logger.debug(`Step 4f-5: PositionTracker has ${state.positionTracker.providerCount} providers`);
|
|
1100
1129
|
// Trigger immediate sync for all categories now that providers are registered
|
|
1101
1130
|
if (state.positionTracker.providerCount > 0) {
|
|
1102
1131
|
void state.positionTracker.syncCategory('LENDING');
|
|
@@ -1118,7 +1147,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1118
1147
|
if (state.notificationService) {
|
|
1119
1148
|
state._versionCheckService.setNotificationService(state.notificationService);
|
|
1120
1149
|
}
|
|
1121
|
-
|
|
1150
|
+
state.logger.debug('Step 4g: VersionCheckService created');
|
|
1122
1151
|
}
|
|
1123
1152
|
// ------------------------------------------------------------------
|
|
1124
1153
|
// Step 4h: EncryptedBackupService (fail-soft)
|
|
@@ -1130,7 +1159,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1130
1159
|
const backupDir = state._config.backup?.dir ?? 'backups';
|
|
1131
1160
|
const backupsDir = isAbsolute(backupDir) ? backupDir : join(dataDir, backupDir);
|
|
1132
1161
|
state._encryptedBackupService = new EncryptedBackupService(dataDir, backupsDir, state.sqlite);
|
|
1133
|
-
|
|
1162
|
+
state.logger.debug('Step 4h: EncryptedBackupService created');
|
|
1134
1163
|
}
|
|
1135
1164
|
}
|
|
1136
1165
|
catch (err) {
|
|
@@ -1143,7 +1172,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1143
1172
|
if (state.sqlite && state.eventBus) {
|
|
1144
1173
|
const { WebhookService } = await import('../services/webhook-service.js');
|
|
1145
1174
|
state.webhookService = new WebhookService(state.sqlite, state.eventBus, () => state.masterPassword);
|
|
1146
|
-
|
|
1175
|
+
state.logger.debug('Step 4i: WebhookService created');
|
|
1147
1176
|
}
|
|
1148
1177
|
}
|
|
1149
1178
|
catch (err) {
|
|
@@ -1171,6 +1200,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1171
1200
|
incomingTxMonitorService: state.incomingTxMonitorService,
|
|
1172
1201
|
actionProviderRegistryRef: { current: state.actionProviderRegistry },
|
|
1173
1202
|
rpcCaller: state.rpcCaller ?? undefined,
|
|
1203
|
+
daemonLogger: state.logger,
|
|
1174
1204
|
});
|
|
1175
1205
|
// [Phase 320] Create ReputationCacheService for REPUTATION_THRESHOLD policy evaluation
|
|
1176
1206
|
const { ReputationCacheService } = await import('../services/erc8004/index.js');
|
|
@@ -1260,7 +1290,7 @@ export async function startDaemon(state, dataDir, masterPassword) {
|
|
|
1260
1290
|
server.once('listening', onListening);
|
|
1261
1291
|
server.once('error', onError);
|
|
1262
1292
|
});
|
|
1263
|
-
|
|
1293
|
+
state.logger.debug(`Step 5: HTTP server listening on ${hostname}:${port}`);
|
|
1264
1294
|
})(), 5_000, 'STEP5_HTTP_SERVER');
|
|
1265
1295
|
// ------------------------------------------------------------------
|
|
1266
1296
|
// Step 6: Background workers + PID (no timeout, fail-soft)
|
|
@@ -1455,7 +1485,7 @@ async function startWorkers(state, dataDir) {
|
|
|
1455
1485
|
const now = Math.floor(Date.now() / 1000);
|
|
1456
1486
|
const result = state.sqlite.prepare('DELETE FROM wallet_credentials WHERE expires_at IS NOT NULL AND expires_at < ?').run(now);
|
|
1457
1487
|
if (result.changes > 0) {
|
|
1458
|
-
|
|
1488
|
+
state.logger.info(`[credential-cleanup] Deleted ${result.changes} expired credential(s)`);
|
|
1459
1489
|
}
|
|
1460
1490
|
}
|
|
1461
1491
|
},
|
|
@@ -1480,10 +1510,10 @@ async function startWorkers(state, dataDir) {
|
|
|
1480
1510
|
runImmediately: true,
|
|
1481
1511
|
handler: async () => { await state._versionCheckService.check(); },
|
|
1482
1512
|
});
|
|
1483
|
-
|
|
1513
|
+
state.logger.debug('Step 6: Version check worker registered');
|
|
1484
1514
|
}
|
|
1485
1515
|
else {
|
|
1486
|
-
|
|
1516
|
+
state.logger.debug('Step 6: Version check disabled');
|
|
1487
1517
|
}
|
|
1488
1518
|
// Register backup worker (auto-backup scheduler)
|
|
1489
1519
|
if (state._encryptedBackupService && state._config.backup.interval > 0) {
|
|
@@ -1498,10 +1528,10 @@ async function startWorkers(state, dataDir) {
|
|
|
1498
1528
|
return;
|
|
1499
1529
|
try {
|
|
1500
1530
|
const info = await backupService.createBackup(masterPwd);
|
|
1501
|
-
|
|
1531
|
+
state.logger.info(`Auto-backup created: ${info.filename} (${info.size} bytes)`);
|
|
1502
1532
|
const pruned = backupService.pruneBackups(retentionCount);
|
|
1503
1533
|
if (pruned > 0) {
|
|
1504
|
-
|
|
1534
|
+
state.logger.info(`Auto-backup: pruned ${pruned} old backup(s), keeping ${retentionCount}`);
|
|
1505
1535
|
}
|
|
1506
1536
|
}
|
|
1507
1537
|
catch (err) {
|
|
@@ -1509,17 +1539,17 @@ async function startWorkers(state, dataDir) {
|
|
|
1509
1539
|
}
|
|
1510
1540
|
},
|
|
1511
1541
|
});
|
|
1512
|
-
|
|
1542
|
+
state.logger.debug(`Step 6: Backup worker registered (interval=${state._config.backup.interval}s, retention=${retentionCount})`);
|
|
1513
1543
|
}
|
|
1514
1544
|
else {
|
|
1515
|
-
|
|
1545
|
+
state.logger.debug('Step 6: Backup worker disabled (interval=0 or no backup service)');
|
|
1516
1546
|
}
|
|
1517
1547
|
state.workers.startAll();
|
|
1518
1548
|
// Write PID file
|
|
1519
1549
|
state.pidPath = join(dataDir, state._config.daemon.pid_file);
|
|
1520
1550
|
writeFileSync(state.pidPath, String(process.pid), 'utf-8');
|
|
1521
|
-
|
|
1522
|
-
|
|
1551
|
+
state.logger.debug(`Step 6: Workers started, PID file written`);
|
|
1552
|
+
state.logger.info(`WAIaaS daemon ready on http://${state._config.daemon.hostname}:${state._config.daemon.port} (PID: ${process.pid})\n` +
|
|
1523
1553
|
` Admin UI: http://${state._config.daemon.hostname}:${state._config.daemon.port}/admin`);
|
|
1524
1554
|
}
|
|
1525
1555
|
catch (err) {
|