@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.
@@ -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
- console.debug('Step 1: Config loaded, daemon lock acquired');
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
- console.debug('Step 2: Schema migration needed, applying...');
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
- console.debug(`Step 2: Settings imported from config.toml (${importResult.imported} keys)`);
92
+ state.logger.debug(`Step 2: Settings imported from config.toml (${importResult.imported} keys)`);
90
93
  }
91
- console.debug('Step 2: Database initialized');
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
- console.debug('Step 2b: Master password verified (DB hash)');
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
- console.debug('Step 2b: Master password verified (keystore migration)');
159
+ state.logger.debug('Step 2b: Master password verified (keystore migration)');
157
160
  }
158
161
  else {
159
- console.debug('Step 2b: First install, no password validation needed');
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
- console.debug('Step 3: Keystore infrastructure verified (master password provided)');
196
+ state.logger.debug('Step 3: Keystore infrastructure verified (master password provided)');
194
197
  }
195
198
  else {
196
- console.debug('Step 3: Keystore infrastructure verified (no master password)');
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. Register built-in defaults (lower priority, appended after config URLs)
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
- // 4. Create AdapterPool with RpcPool
259
+ // 5. Create AdapterPool with RpcPool
237
260
  state.adapterPool = new AdapterPool(state.rpcPool);
238
- console.debug(`Step 4: AdapterPool created with RpcPool (${state.rpcPool.getNetworks().length} networks seeded)`);
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
- console.debug('Step 4b: Workflow instances created (DelayQueue + ApprovalWorkflow)');
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
- console.debug('Step 4c: JWT secret manager initialized, master password hashed');
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
- console.debug('Step 4c-2: KillSwitchService initialized');
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
- console.debug(`Step 4d: NotificationService initialized (${channelNames.length} channels: ${channelNames.join(', ') || 'none'})`);
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
- console.debug('Step 4c-3: AutoStop engine started');
417
+ state.logger.debug('Step 4c-3: AutoStop engine started');
395
418
  }
396
419
  else {
397
- console.debug('Step 4c-3: AutoStop engine disabled');
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
- console.debug('Step 4c-3b: AdminStatsService created');
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
- console.debug('Step 4c-4: Balance monitor started');
476
+ state.logger.debug('Step 4c-4: Balance monitor started');
454
477
  }
455
478
  else {
456
- console.debug('Step 4c-4: Balance monitor disabled');
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
- console.debug('Step 4c-5: Telegram Bot started');
514
+ state.logger.debug('Step 4c-5: Telegram Bot started');
492
515
  }
493
516
  else {
494
- console.debug('Step 4c-5: Telegram Bot disabled');
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
- console.debug('Step 4c-6: WalletConnect service initialized');
538
+ state.logger.debug('Step 4c-6: WalletConnect service initialized');
516
539
  }
517
540
  else {
518
- console.debug('Step 4c-6: WalletConnect disabled (no project_id)');
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
- console.debug('Step 4c-7: WcSigningBridge initialized');
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
- console.debug('Step 4c-8: signResponseHandler injected into TelegramBotService');
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
- console.debug('Step 4c-8: WalletNotificationChannel injected into NotificationService');
600
- console.debug('Step 4c-8: Signing SDK initialized (ApprovalChannelRouter + channels)');
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
- console.debug('Step 4c-8: Signing SDK disabled');
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
- console.debug('Step 4c-9: Incoming TX monitor started');
744
+ state.logger.debug('Step 4c-9: Incoming TX monitor started');
722
745
  }
723
746
  else {
724
- console.debug('Step 4c-9: Incoming TX monitor disabled');
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
- console.debug('Step 4c-10: AsyncPollingService initialized (with callbacks)');
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
- console.debug('Step 4c-10.5: Position tracker started');
803
+ state.logger.debug('Step 4c-10.5: Position tracker started');
781
804
  }
782
805
  else {
783
- console.debug('Step 4c-10.5: Position tracker disabled');
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
- console.debug('Step 4c-11: DeFi monitor service started with', state.defiMonitorService.monitorCount, 'monitors');
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
- console.debug(`Step 4e: PriceOracle initialized (Pyth primary${coingeckoOracle ? ' + CoinGecko fallback' : ''})`);
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
- console.debug('Step 4e-2: ForexRateService initialized (30min cache)');
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 { ConsoleLogger } = await import('@waiaas/core');
927
- const actionLogger = new ConsoleLogger('actions');
928
- const builtIn = registerBuiltInProviders(state.actionProviderRegistry, state._settingsService, { rpcCaller, logger: actionLogger });
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
- console.debug('Step 4f-pm: Polymarket providers registered (order + ctf)');
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
- console.debug(`Step 4f: ActionProviderRegistry initialized (${builtIn.loaded.length} built-in, ${result.loaded.length} plugins loaded, ${result.failed.length} failed)`);
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
- console.debug(`Step 4f: ActionProviderRegistry initialized (${builtIn.loaded.length} built-in, no plugins directory)`);
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
- console.debug('Step 4f-2: Bridge status trackers registered (bridge + bridge-monitoring)');
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
- console.debug('Step 4f-2a: Across bridge status trackers registered (across-bridge + across-bridge-monitoring)');
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
- console.debug('Step 4f-3: Lido withdrawal tracker registered');
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
- console.debug('Step 4f-3: Jito epoch tracker registered');
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
- console.debug('Step 4f-4: GasConditionTracker registered');
1105
+ state.logger.debug('Step 4f-4: GasConditionTracker registered');
1077
1106
  }
1078
1107
  else {
1079
- console.debug('Step 4f-4: GasConditionTracker disabled');
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
- console.debug(`Step 4f-5: Registered ${meta.name} with PositionTracker`);
1125
+ state.logger.debug(`Step 4f-5: Registered ${meta.name} with PositionTracker`);
1097
1126
  }
1098
1127
  }
1099
- console.debug(`Step 4f-5: PositionTracker has ${state.positionTracker.providerCount} providers`);
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
- console.debug('Step 4g: VersionCheckService created');
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
- console.debug('Step 4h: EncryptedBackupService created');
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
- console.debug('Step 4i: WebhookService created');
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
- console.debug(`Step 5: HTTP server listening on ${hostname}:${port}`);
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
- console.log(`[credential-cleanup] Deleted ${result.changes} expired credential(s)`);
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
- console.debug('Step 6: Version check worker registered');
1513
+ state.logger.debug('Step 6: Version check worker registered');
1484
1514
  }
1485
1515
  else {
1486
- console.debug('Step 6: Version check disabled');
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
- console.log(`Auto-backup created: ${info.filename} (${info.size} bytes)`);
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
- console.log(`Auto-backup: pruned ${pruned} old backup(s), keeping ${retentionCount}`);
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
- console.debug(`Step 6: Backup worker registered (interval=${state._config.backup.interval}s, retention=${retentionCount})`);
1542
+ state.logger.debug(`Step 6: Backup worker registered (interval=${state._config.backup.interval}s, retention=${retentionCount})`);
1513
1543
  }
1514
1544
  else {
1515
- console.debug('Step 6: Backup worker disabled (interval=0 or no backup service)');
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
- console.debug(`Step 6: Workers started, PID file written`);
1522
- console.log(`WAIaaS daemon ready on http://${state._config.daemon.hostname}:${state._config.daemon.port} (PID: ${process.pid})\n` +
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) {