import { unitsToNumber } from './assets.mjs'; import { summarizeFundingObservations } from './funding-observations.mjs'; import { resolveDashboardRequestAuth } from './operator-dashboard-auth.mjs'; import { deriveServiceHealth, inferServiceFreshnessTimestamp as inferRuntimeFreshnessTimestamp } from './runtime-health.mjs'; export const DASHBOARD_LIVE_QUOTE_LIMIT = 10; const DECIMAL_SCALE = 18; const DECIMAL_FACTOR = 10n ** BigInt(DECIMAL_SCALE); const ALERT_SEVERITY_ORDER = { critical: 3, warning: 2, info: 1, }; const CREDITED_FUNDING_STATUSES = new Set(['CREDITED', 'COMPLETED', 'FINALIZED', 'SETTLED']); const CONTROL_DEFINITIONS = [ { service: 'near-intents-ingest', action: 'reconnect', method: 'POST', path: '/reconnect', label: 'Reconnect Ingest', description: 'Reconnect the ingest websocket without restarting the deployment.', page: 'system', risk_class: 'safe', }, { service: 'market-reference-ingest', action: 'refresh', method: 'POST', path: '/refresh', label: 'Refresh Price', description: 'Fetch the latest BTC/EUR reference price.', page: 'funds', risk_class: 'safe', }, { service: 'inventory-sync', action: 'refresh', method: 'POST', path: '/refresh', label: 'Refresh Inventory', description: 'Sync verifier balances into the latest inventory snapshot.', page: 'funds', risk_class: 'safe', }, { service: 'liquidity-manager', action: 'refresh', method: 'POST', path: '/refresh', label: 'Refresh Liquidity', description: 'Refresh bridge deposit handles, deposits, and tracked withdrawals.', page: 'funds', risk_class: 'safe', }, { service: 'liquidity-manager', action: 'pause', method: 'POST', path: '/pause', label: 'Pause Liquidity', description: 'Pause non-fund-moving liquidity state refreshes.', page: 'system', risk_class: 'safe', }, { service: 'liquidity-manager', action: 'resume', method: 'POST', path: '/resume', label: 'Resume Liquidity', description: 'Resume liquidity state refreshes.', page: 'system', risk_class: 'safe', }, { service: 'liquidity-manager', action: 'pause-funding-observer', method: 'POST', path: '/pause-funding-observer', label: 'Pause Funding Observer', description: 'Pause pre-credit funding observations without touching spendable truth.', page: 'funds', risk_class: 'safe', }, { service: 'liquidity-manager', action: 'resume-funding-observer', method: 'POST', path: '/resume-funding-observer', label: 'Resume Funding Observer', description: 'Resume pre-credit funding observations.', page: 'funds', risk_class: 'safe', }, { service: 'liquidity-manager', action: 'freeze-withdrawals', method: 'POST', path: '/freeze-withdrawals', label: 'Update Withdrawal Freeze', description: 'Toggle withdrawal freeze without submitting live withdrawals.', page: 'funds', risk_class: 'safe', }, { service: 'liquidity-manager', action: 'withdrawal-estimate', method: 'POST', path: '/withdrawal-estimate', label: 'Estimate Withdrawal', description: 'Estimate a bridge withdrawal without moving funds.', page: 'funds', risk_class: 'safe', }, { service: 'trade-executor', action: 'reconnect', method: 'POST', path: '/reconnect', label: 'Reconnect Relay', description: 'Reconnect the trade-executor solver relay websocket.', page: 'system', risk_class: 'safe', }, { service: 'trade-executor', action: 'pause', method: 'POST', path: '/pause', label: 'Pause Executor', description: 'Pause trade-executor command consumption without moving funds.', page: 'system', risk_class: 'safe', }, { service: 'trade-executor', action: 'resume', method: 'POST', path: '/resume', label: 'Resume Executor', description: 'Resume trade-executor command consumption.', page: 'system', risk_class: 'safe', }, { service: 'trade-executor', action: 'disarm', method: 'POST', path: '/disarm', label: 'Disarm Executor', description: 'Force the executor into a non-fund-moving safe state.', page: 'system', risk_class: 'safe', }, { service: 'ops-sentinel', action: 'pause', method: 'POST', path: '/pause', label: 'Pause Alerts', description: 'Pause alert evaluation without changing trade arming state.', page: 'system', risk_class: 'safe', }, { service: 'ops-sentinel', action: 'resume', method: 'POST', path: '/resume', label: 'Resume Alerts', description: 'Resume alert evaluation.', page: 'system', risk_class: 'safe', }, ]; const SERVICE_DEFINITIONS = [ ['near-intents-ingest', 'Intents Ingest', 'nearIntentsControlBaseUrl'], ['market-reference-ingest', 'Reference Price', 'marketReferenceControlBaseUrl'], ['inventory-sync', 'Inventory Sync', 'inventorySyncControlBaseUrl'], ['liquidity-manager', 'Liquidity Manager', 'liquidityManagerControlBaseUrl'], ['history-writer', 'History Writer', 'historyWriterControlBaseUrl'], ['ops-sentinel', 'Ops Sentinel', 'opsSentinelControlBaseUrl'], ['strategy-engine', 'Strategy Engine', 'strategyEngineControlBaseUrl'], ['trade-executor', 'Trade Executor', 'tradeExecutorControlBaseUrl'], ]; export function resolveDashboardAuth({ mode = 'stub' } = {}) { return resolveDashboardRequestAuth({ mode }); } export function listDashboardControls({ page = null } = {}) { const controls = CONTROL_DEFINITIONS.map((definition) => ({ ...definition })); if (!page) return controls; return controls.filter((definition) => definition.page === page); } export function resolveDashboardControl({ service, action }) { return CONTROL_DEFINITIONS.find((definition) => ( definition.service === service && definition.action === action )) || null; } export function listDashboardServices(config) { return SERVICE_DEFINITIONS.map(([service, label, configKey]) => ({ service, label, base_url: config[configKey], })); } export function createDashboardLiveState({ config, recentQuotes = [], latestMarketPrice = null, latestInventory = null, successfulTradeCount = 0, lastSuccessfulTradeAt = null, activeAlerts = [], } = {}) { const state = { active_pair: config.activePair, btc_asset: config.tradingBtc, eure_asset: config.tradingEure, quote_limit: config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT, recent_quotes: recentQuotes.slice(0, config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT), latest_market_price: latestMarketPrice?.payload || latestMarketPrice || null, latest_inventory: latestInventory?.payload || latestInventory || null, successful_trade_count: Number(successfulTradeCount || 0), last_successful_trade_at: lastSuccessfulTradeAt || null, active_alerts: new Map(), }; for (const alert of activeAlerts) { if (!alert) continue; state.active_alerts.set(buildAlertKey(alert), alert); } return state; } export function applyDashboardLiveEvent(state, { topic, event }) { if (!event?.payload) return []; switch (topic) { case 'norm.swap_demand': { const quote = normalizeLiveQuote(event.payload, event); if (!quote) return []; state.recent_quotes = appendUniqueRecentQuote(state.recent_quotes, quote, state.quote_limit); return [{ type: 'quotes.recent', recent_quotes: state.recent_quotes, }]; } case 'ref.market_price': state.latest_market_price = { ...event.payload, observed_at: event.observed_at || event.payload.observed_at || null, ingested_at: event.ingested_at || null, }; return [{ type: 'status_bar.updated', status_bar: buildLiveStatusBar(state), }]; case 'state.intent_inventory': state.latest_inventory = { ...event.payload, observed_at: event.observed_at || event.payload.synced_at || null, ingested_at: event.ingested_at || null, }; return [{ type: 'status_bar.updated', status_bar: buildLiveStatusBar(state), }]; case 'ops.alert': { const alert = normalizeAlert(event.payload); const key = buildAlertKey(alert); if (alert.status === 'raised') { state.active_alerts.set(key, alert); } else if (alert.status === 'cleared') { state.active_alerts.delete(key); } return [{ type: 'alerts.updated', alerts: { active_alert_count: state.active_alerts.size, highest_alert_severity: highestAlertSeverity([...state.active_alerts.values()]), }, }, { type: 'status_bar.updated', status_bar: buildLiveStatusBar(state), }]; } case 'exec.trade_result': if (event.payload.status !== 'submitted') return []; state.successful_trade_count += 1; state.last_successful_trade_at = event.observed_at || event.ingested_at || new Date().toISOString(); return [{ type: 'status_bar.updated', status_bar: buildLiveStatusBar(state), }]; default: return []; } } export function buildDashboardBootstrap({ config, auth, portfolioMetric, inventorySnapshot, marketPrice, recentQuotes, successfulTrades, successfulTradeSummary, fundingObservations, recentDepositStatuses, recentTradeDecisions, recentAlertTransitions, serviceSnapshots, sourceErrors = [], } = {}) { const servicesByName = Object.fromEntries( (serviceSnapshots || []).map((snapshot) => [snapshot.service, snapshot]), ); const activeAlerts = normalizeAlertList( servicesByName['ops-sentinel']?.state?.active_alerts || [], ); const recentAlerts = normalizeAlertList( servicesByName['ops-sentinel']?.state?.recent_transitions || recentAlertTransitions?.map((entry) => entry.payload) || [], ); const profitability = buildProfitabilitySummary({ metric: portfolioMetric, successfulTradeSummary, }); const balances = buildBalanceSummary({ inventorySnapshot, marketPrice, config, }); const funding = buildFundingSummary({ config, fundingObservations, recentDepositStatuses, liquidityState: servicesByName['liquidity-manager']?.state || {}, }); const tradesPage = normalizeSuccessfulTradesPage({ config, successfulTrades, }); return { session: auth, source_errors: sourceErrors, default_page: 'funds', status_bar: buildStatusBar({ config, profitability, inventorySnapshot, marketPrice, activeAlerts, servicesByName, }), funds: { profitability, balances, funding, recent_deposits: funding.credited_deposits, recent_withdrawals: buildRecentWithdrawals({ config, liquidityState: servicesByName['liquidity-manager']?.state || {}, }), trade_asset_changes: buildTradeAssetChanges({ config, trades: tradesPage.items, }), recent_quotes: (recentQuotes || []).slice(0, config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT), successful_trades: tradesPage, controls: listDashboardControls({ page: 'funds' }), caveats: profitability.caveats, }, strategy: buildStrategySummary({ servicesByName, activeAlerts, recentTradeDecisions, }), system: buildSystemSummary({ servicesByName, activeAlerts, recentAlerts, }), }; } export function buildProfitabilitySummary({ metric, successfulTradeSummary } = {}) { const externalCashFlows = metric?.payload?.external_cash_flows || {}; const externalFlowCount = Number(externalCashFlows.flow_count || 0); const externalFlowAdjusted = externalFlowCount > 0; const summary = { computed_at: metric?.computed_at || null, current_total_portfolio_value_eure: metric?.payload?.current_portfolio_value_eure || null, deposit_baseline_value_eure: metric?.payload?.baseline_portfolio_value_eure_at_baseline_price || null, simple_hold_value_eure: metric?.payload?.baseline_portfolio_value_eure_at_current_price || null, pnl_vs_deposit_baseline_eure: null, pnl_vs_simple_hold_eure: null, market_move_contribution_eure: null, trading_contribution_eure: null, baseline_anchor_at: metric?.baseline_anchor_at || null, baseline_status: metric?.baseline_status || metric?.payload?.baseline_status || 'unavailable', external_flow_adjusted: externalFlowAdjusted, external_flow_count: externalFlowCount, external_deposit_count: Number(externalCashFlows.deposit_count || 0), external_withdrawal_count: Number(externalCashFlows.withdrawal_count || 0), latest_external_flow_at: externalCashFlows.latest_effective_at || null, net_external_flow_value_eure: externalCashFlows.net_value_eure_at_flow_time || '0', recent_trade_count: successfulTradeSummary?.total ?? metric?.payload?.result_count ?? 0, last_successful_trade_at: successfulTradeSummary?.last_successful_trade_at || null, caveats: [ 'Portfolio PnL is truthful to the current durable inventory and reference price path.', 'Fees and per-trade realized net settlement deltas are not fully tracked yet.', ], }; if (summary.current_total_portfolio_value_eure == null) { summary.caveats.unshift('Profitability is unavailable until durable portfolio metrics exist.'); return summary; } if (summary.deposit_baseline_value_eure) { summary.pnl_vs_deposit_baseline_eure = formatDecimalDifference( summary.current_total_portfolio_value_eure, summary.deposit_baseline_value_eure, ); } if (summary.simple_hold_value_eure) { summary.pnl_vs_simple_hold_eure = formatDecimalDifference( summary.current_total_portfolio_value_eure, summary.simple_hold_value_eure, ); } if (summary.deposit_baseline_value_eure && summary.simple_hold_value_eure) { summary.market_move_contribution_eure = formatDecimalDifference( summary.simple_hold_value_eure, summary.deposit_baseline_value_eure, ); } if (summary.simple_hold_value_eure) { summary.trading_contribution_eure = formatDecimalDifference( summary.current_total_portfolio_value_eure, summary.simple_hold_value_eure, ); } if (summary.external_flow_adjusted) { summary.caveats.unshift( `Later credited deposits and completed withdrawals (${summary.external_flow_count}) are treated as external cash flows, not trading PnL.`, ); } return summary; } export function buildLiveStatusBar(state) { return { latest_reference_price_eure_per_btc: state.latest_market_price?.eure_per_btc || null, market_observed_at: state.latest_market_price?.observed_at || state.latest_market_price?.ingested_at || null, market_freshness_ms: ageMs( state.latest_market_price?.observed_at || state.latest_market_price?.ingested_at, ), inventory_observed_at: state.latest_inventory?.synced_at || state.latest_inventory?.observed_at || state.latest_inventory?.ingested_at || null, inventory_freshness_ms: ageMs( state.latest_inventory?.synced_at || state.latest_inventory?.observed_at || state.latest_inventory?.ingested_at, ), current_total_portfolio_value_eure: computeCurrentPortfolioValue({ inventory: state.latest_inventory, marketPrice: state.latest_market_price, btcAsset: state.btc_asset, eureAsset: state.eure_asset, }), active_alert_count: state.active_alerts.size, highest_alert_severity: highestAlertSeverity([...state.active_alerts.values()]), recent_trade_count: state.successful_trade_count, last_successful_trade_at: state.last_successful_trade_at, }; } function buildStatusBar({ config, profitability, inventorySnapshot, marketPrice, activeAlerts, servicesByName, }) { return { active_pair: config.activePair, latest_reference_price_eure_per_btc: marketPrice?.payload?.eure_per_btc || null, market_observed_at: marketPrice?.payload?.observed_at || marketPrice?.ingested_at || null, market_freshness_ms: ageMs(marketPrice?.payload?.observed_at || marketPrice?.ingested_at), inventory_observed_at: inventorySnapshot?.payload?.synced_at || inventorySnapshot?.ingested_at || null, inventory_freshness_ms: ageMs( inventorySnapshot?.payload?.synced_at || inventorySnapshot?.ingested_at, ), active_alert_count: activeAlerts.length, highest_alert_severity: highestAlertSeverity(activeAlerts), strategy_armed: servicesByName['strategy-engine']?.state?.armed ?? null, executor_armed: servicesByName['trade-executor']?.state?.armed ?? null, current_total_portfolio_value_eure: profitability.current_total_portfolio_value_eure, recent_trade_count: profitability.recent_trade_count, last_successful_trade_at: profitability.last_successful_trade_at, }; } function buildBalanceSummary({ inventorySnapshot, marketPrice, config }) { const inventory = inventorySnapshot?.payload || {}; const spendable = inventory.spendable || {}; const pendingInbound = inventory.pending_inbound || {}; const pendingOutbound = inventory.pending_outbound || {}; return { synced_at: inventory.synced_at || inventorySnapshot?.ingested_at || null, reconciliation_status: inventory.reconciliation_status || null, items: [...config.assetRegistry.values()].map((asset) => { const spendableUnits = String(spendable[asset.assetId] || '0'); const pendingInboundUnits = String(pendingInbound[asset.assetId] || '0'); const pendingOutboundUnits = String(pendingOutbound[asset.assetId] || '0'); return { asset_id: asset.assetId, symbol: asset.symbol, chain: asset.chain, spendable_units: spendableUnits, spendable: formatUnits(spendableUnits, asset.decimals), pending_inbound_units: pendingInboundUnits, pending_inbound: formatUnits(pendingInboundUnits, asset.decimals), pending_outbound_units: pendingOutboundUnits, pending_outbound: formatUnits(pendingOutboundUnits, asset.decimals), eur_value_eure: valueAssetInEur({ asset, units: spendableUnits, marketPrice: marketPrice?.payload || marketPrice || null, }), }; }), }; } function buildFundingSummary({ config, fundingObservations, recentDepositStatuses, liquidityState }) { const observations = (fundingObservations || []).map((entry) => entry.payload || entry); const summary = summarizeFundingObservations(observations, { now: new Date().toISOString(), }); const observerItems = observations.map((observation) => normalizeFundingObservationForUi({ config, observation, })); const depositItems = buildRecentDepositItems({ config, recentDepositStatuses, liquidityState, }); const recentFundingActivity = mergeFundingActivityItems({ observerItems, depositItems, }); return { latest_observed_at: latestFundingActivityAt(recentFundingActivity, summary.latest_funding_observation_at), control_state: { paused: liquidityState?.paused ?? null, funding_observer_paused: liquidityState?.funding_observer_paused ?? null, withdrawals_frozen: liquidityState?.withdrawals_frozen ?? null, withdrawal_defaults: liquidityState?.withdrawal_defaults || {}, }, handles: Object.entries(liquidityState?.deposit_addresses || {}).map(([chain, details]) => ({ chain, asset_id: config.tradingBtc.chain === chain ? config.tradingBtc.assetId : config.tradingEure.assetId, symbol: config.tradingBtc.chain === chain ? config.tradingBtc.symbol : config.tradingEure.symbol, address: details?.address || null, memo: details?.memo || null, refreshed_at: details?.refreshed_at || null, })), credited_deposits: recentFundingActivity .filter((observation) => CREDITED_FUNDING_STATUSES.has(String(observation?.status || '').toUpperCase())) .sort((left, right) => sortTimestamps( fundingActivityTimestamp(right), fundingActivityTimestamp(left), )) .slice(0, 10) .map((observation) => ({ ...observation })), pre_credit_by_asset: Object.values(summary.funding_visibility_by_asset || {}).map((entry) => { const asset = config.assetRegistry.get(entry.asset_id); return { asset_id: entry.asset_id, symbol: asset?.symbol || entry.asset_id, pre_credit_total_units: entry.pre_credit_total || '0', pre_credit_total: formatUnits(entry.pre_credit_total || '0', asset?.decimals || 0), latest_status: entry.latest_status, latest_observation_at: entry.latest_observation_at, }; }), pre_credit_by_handle: Object.values(summary.funding_observations_by_handle || {}).map((entry) => { const asset = config.assetRegistry.get(entry.asset_id); return { funding_handle: entry.funding_handle, chain: entry.chain, asset_id: entry.asset_id, symbol: asset?.symbol || entry.asset_id, pre_credit_total_units: entry.pre_credit_total || '0', pre_credit_total: formatUnits(entry.pre_credit_total || '0', asset?.decimals || 0), latest_status: entry.latest_status, latest_observation_at: entry.latest_observation_at, observation_count: entry.observations?.length || 0, }; }), recent_observations: recentFundingActivity .sort((left, right) => sortTimestamps( fundingActivityTimestamp(right), fundingActivityTimestamp(left), )) .slice(0, 10) .map((observation) => ({ ...observation })), }; } function buildRecentWithdrawals({ config, liquidityState }) { return Object.values(liquidityState?.tracked_withdrawals || {}) .sort((left, right) => sortTimestamps( right.last_checked_at || right.submitted_at || right.noted_at, left.last_checked_at || left.submitted_at || left.noted_at, )) .slice(0, 10) .map((withdrawal) => { const asset = config.assetRegistry.get(withdrawal.asset_id); return { withdrawal_hash: withdrawal.withdrawal_hash, asset_id: withdrawal.asset_id, symbol: asset?.symbol || withdrawal.asset_id, chain: withdrawal.chain || null, amount_units: String(withdrawal.amount || '0'), amount: formatUnits(withdrawal.amount || '0', asset?.decimals || 0), status: withdrawal.status || null, address: withdrawal.address || null, submitted_at: withdrawal.submitted_at || null, last_checked_at: withdrawal.last_checked_at || null, noted_at: withdrawal.noted_at || null, }; }); } function buildTradeAssetChanges({ config, trades }) { return (trades || []).slice(0, 10).map((trade) => { const assetIn = config.assetRegistry.get(trade.asset_in); const assetOut = config.assetRegistry.get(trade.asset_out); return { observed_at: trade.observed_at, quote_id: trade.quote_id, request_kind: trade.request_kind, asset_in: trade.asset_in, asset_in_symbol: assetIn?.symbol || trade.asset_in, amount_in_units: trade.amount_in, amount_in: formatUnits(trade.amount_in || '0', assetIn?.decimals || 0), asset_out: trade.asset_out, asset_out_symbol: assetOut?.symbol || trade.asset_out, amount_out_units: trade.amount_out, amount_out: formatUnits(trade.amount_out || '0', assetOut?.decimals || 0), }; }); } function normalizeSuccessfulTradesPage({ config, successfulTrades }) { return { ...successfulTrades, items: (successfulTrades?.items || []).map((trade) => normalizeTradeForUi({ config, trade, })), }; } function buildStrategySummary({ servicesByName, activeAlerts, recentTradeDecisions = [] }) { const strategyState = servicesByName['strategy-engine']?.state || {}; const executorState = servicesByName['trade-executor']?.state || {}; const durableDecisionsById = new Map( (recentTradeDecisions || []) .map((entry) => normalizeDecision({ ...(entry.payload || {}), decision_at: entry?.payload?.decision_at || entry?.observed_at || entry?.ingested_at || null, })) .filter((entry) => entry?.decision_id) .map((entry) => [entry.decision_id, entry]), ); const recentDecisions = (strategyState.recent_decisions || []).slice(0, 20).map((decision) => { const durableDecision = durableDecisionsById.get(decision?.decision_id) || null; return normalizeDecision({ ...(durableDecision || {}), ...(decision || {}), decision_at: decision?.decision_at || durableDecision?.decision_at || null, }); }); const latestDecision = normalizeDecision({ ...(durableDecisionsById.get(strategyState.latest_decision?.decision_id) || {}), ...(strategyState.latest_decision || {}), decision_at: strategyState.latest_decision?.decision_at || durableDecisionsById.get(strategyState.latest_decision?.decision_id)?.decision_at || null, }); return { strategy_state: { armed: strategyState.armed ?? null, paused: strategyState.paused ?? null, threshold_pct: strategyState.threshold_pct ?? null, max_notional_eure: strategyState.max_notional_eure ?? null, latest_decision: latestDecision?.decision_id ? latestDecision : null, recent_decisions: recentDecisions.length ? recentDecisions : [...durableDecisionsById.values()].slice(0, 20), skipped_counts: strategyState.skipped_counts || {}, durable_control_state: strategyState.durable_control_state || null, }, executor_state: { armed: executorState.armed ?? null, paused: executorState.paused ?? null, draining: executorState.draining ?? null, in_flight_count: executorState.in_flight_count ?? 0, completed_count: executorState.completed_count ?? 0, last_command: executorState.last_command || null, last_venue_response: executorState.last_venue_response || null, last_error: executorState.last_error || null, signer_registered: executorState.signer_registered ?? null, account_id: executorState.account_id || null, signer_public_key: executorState.signer_public_key || null, }, relevant_alerts: activeAlerts.filter((alert) => ( ['strategy-engine', 'trade-executor', 'liquidity-manager'].includes(alert.service_scope) )), omitted_controls: [ 'Strategy arm and disarm are intentionally absent in this turn.', 'Executor arm and drain are intentionally absent in this turn.', 'Live withdrawal submission is intentionally absent in this turn.', ], }; } function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts }) { const historyWriterState = servicesByName['history-writer']?.state || {}; const sentinelServiceHealth = new Map( (servicesByName['ops-sentinel']?.state?.service_health || []).map((entry) => [entry.service, entry]), ); return { service_health: Object.values(servicesByName).map((snapshot) => ( summarizeServiceSnapshot(snapshot, { authoritativeHealth: sentinelServiceHealth.get(snapshot.service) || null, activeAlerts, }) )), alerts: { active: activeAlerts, recent: recentAlerts, }, persistence: { database_connectivity: historyWriterState.database_connectivity ?? null, last_write_at: historyWriterState.last_write_at || null, last_alert_write_at: historyWriterState.last_alert_write_at || null, last_funding_observation_write_at: historyWriterState.last_funding_observation_write_at || null, last_metrics_at: historyWriterState.last_metrics_at || null, latest_portfolio_metrics: historyWriterState.latest_portfolio_metrics || null, offsets: historyWriterState.offsets || {}, metrics_error: historyWriterState.metrics_error || null, }, controls: listDashboardControls({ page: 'system' }), }; } function summarizeServiceSnapshot(snapshot, { authoritativeHealth = null, activeAlerts = [] } = {}) { const state = snapshot.state || {}; const health = snapshot.health || {}; const derived = authoritativeHealth || deriveServiceHealth({ service: snapshot.service, snapshot, activeAlerts: activeAlerts.filter((alert) => alert.service_scope === snapshot.service), }); const freshnessAt = derived.freshness_at || inferServiceFreshnessTimestamp(snapshot.service, state, health); return { service: snapshot.service, label: snapshot.label, base_url: snapshot.base_url, reachable: snapshot.reachable, health_ok: derived.health_ok, health_status: derived.status, health_reasons: derived.reasons || [], highest_alert_severity: derived.highest_alert_severity || null, paused: derived.paused ?? state.paused ?? health.paused ?? null, armed: derived.armed ?? state.armed ?? null, draining: state.draining ?? null, freshness_at: freshnessAt, freshness_age_ms: derived.freshness_age_ms ?? ageMs(freshnessAt), last_error: state.last_error || health.last_error || null, summary: buildServiceSummary(snapshot.service, state), }; } function buildServiceSummary(service, state) { switch (service) { case 'near-intents-ingest': return { connected: state.ingest?.connected ?? null, reconnect_count: state.ingest?.reconnect_count ?? null, pair_filter: state.pair_filter?.pair_filter || null, last_message_at: state.ingest?.last_message_at || null, last_matching_quote_at: state.ingest?.last_matching_quote_at || null, last_published_at: state.ingest?.last_published_at || null, }; case 'market-reference-ingest': return { last_published_at: state.last_published_at || null, source_used: state.kraken?.healthy ? 'kraken' : state.coingecko?.healthy ? 'coingecko' : null, }; case 'inventory-sync': return { last_sync_at: state.last_sync_at || null, reconciliation_status: state.last_snapshot?.reconciliation_status || null, }; case 'liquidity-manager': return { last_refresh_at: state.last_refresh_at || null, funding_observer_paused: state.funding_observer_paused ?? null, withdrawals_frozen: state.withdrawals_frozen ?? null, }; case 'history-writer': return { last_write_at: state.last_write_at || null, last_alert_write_at: state.last_alert_write_at || null, database_connectivity: state.database_connectivity ?? null, }; case 'ops-sentinel': return { last_event_at: state.last_event_at || null, last_runtime_eval_at: state.last_runtime_eval_at || null, active_alert_count: state.active_alerts?.length || 0, stale: state.stale ?? null, }; case 'strategy-engine': return { latest_decision_id: state.latest_decision?.decision_id || null, threshold_pct: state.threshold_pct ?? null, max_notional_eure: state.max_notional_eure ?? null, }; case 'trade-executor': return { in_flight_count: state.in_flight_count ?? 0, completed_count: state.completed_count ?? 0, signer_registered: state.signer_registered ?? null, relay_connected: state.relay?.connected ?? null, relay_last_message_at: state.relay?.last_message_at || null, }; case 'operator-dashboard': return { source_error_count: state.source_error_count ?? 0, last_source_error_at: state.last_source_error_at || null, last_bootstrap_at: state.last_bootstrap_at || null, }; default: return {}; } } function inferServiceFreshnessTimestamp(service, state, health) { return inferRuntimeFreshnessTimestamp(service, state, health); } function normalizeTradeForUi({ config, trade }) { const assetIn = config.assetRegistry.get(trade.asset_in); const assetOut = config.assetRegistry.get(trade.asset_out); return { ...trade, asset_in_symbol: assetIn?.symbol || trade.asset_in, asset_out_symbol: assetOut?.symbol || trade.asset_out, amount_in_display: formatUnits(trade.amount_in || '0', assetIn?.decimals || 0), amount_out_display: formatUnits(trade.amount_out || '0', assetOut?.decimals || 0), }; } function buildRecentDepositItems({ config, recentDepositStatuses, liquidityState }) { const recentItems = (recentDepositStatuses || []).map((entry) => normalizeDepositStatusForUi({ config, depositStatus: entry, })); const itemsByKey = new Map( recentItems.map((item) => [buildFundingActivityKey(item), item]), ); for (const deposit of Object.values(liquidityState?.deposits || {})) { const fallbackItem = normalizeLiquidityDepositForUi({ config, deposit, observedAt: liquidityState?.last_refresh_at || null, }); const key = buildFundingActivityKey(fallbackItem); if (!itemsByKey.has(key)) { itemsByKey.set(key, fallbackItem); } } return [...itemsByKey.values()]; } function mergeFundingActivityItems({ observerItems, depositItems }) { const merged = new Map(); for (const item of depositItems || []) { merged.set(buildFundingActivityKey(item), item); } for (const item of observerItems || []) { merged.set(buildFundingActivityKey(item), item); } return [...merged.values()]; } function latestFundingActivityAt(items, fallback = null) { let latest = fallback; for (const item of items || []) { if (sortTimestamps(fundingActivityTimestamp(item), latest) > 0) { latest = fundingActivityTimestamp(item); } } return latest; } function fundingActivityTimestamp(item) { return item?.last_seen_at || item?.credited_at || item?.first_seen_at || null; } function buildFundingActivityKey(item) { return [ item?.tx_hash || 'no-tx', item?.chain || 'no-chain', item?.asset_id || 'no-asset', item?.funding_handle || 'no-handle', item?.amount_units || 'no-amount', ].join('|'); } function normalizeFundingObservationForUi({ config, observation }) { const asset = config.assetRegistry.get(observation.asset_id); return { funding_observation_id: observation.funding_observation_id, asset_id: observation.asset_id, symbol: asset?.symbol || observation.asset_id, chain: observation.chain, funding_handle: observation.funding_handle, tx_hash: observation.tx_hash, status: observation.status, amount_units: observation.amount, amount: formatUnits(observation.amount || '0', asset?.decimals || 0), confirmations: observation.confirmations, first_seen_at: observation.first_seen_at, last_seen_at: observation.last_seen_at, credited_at: observation.credited_at || null, }; } function normalizeDepositStatusForUi({ config, depositStatus }) { const payload = depositStatus?.payload || {}; const details = payload.details || {}; return normalizeLiquidityDepositForUi({ config, deposit: { tx_hash: details.tx_hash || null, chain: payload.chain || details.chain || null, asset_id: payload.asset_id || details.asset_id || null, amount: details.amount || '0', address: details.address || details.deposit_address || null, status: payload.status || details.status || null, }, observedAt: depositStatus?.observed_at || depositStatus?.ingested_at || null, }); } function normalizeLiquidityDepositForUi({ config, deposit, observedAt }) { const asset = config.assetRegistry.get(deposit?.asset_id); const status = deposit?.status || null; const timestamp = observedAt || null; return { funding_observation_id: null, asset_id: deposit?.asset_id || null, symbol: asset?.symbol || deposit?.asset_id || null, chain: deposit?.chain || null, funding_handle: deposit?.address || null, tx_hash: deposit?.tx_hash || null, status, amount_units: String(deposit?.amount || '0'), amount: formatUnits(deposit?.amount || '0', asset?.decimals || 0), confirmations: null, first_seen_at: timestamp, last_seen_at: timestamp, credited_at: CREDITED_FUNDING_STATUSES.has(String(status || '').toUpperCase()) ? timestamp : null, }; } function normalizeDecision(decision) { if (!decision) return null; return { decision_id: decision.decision_id || null, decision_at: decision.decision_at || null, quote_id: decision.quote_id || null, pair: decision.pair || null, direction: decision.direction || null, request_kind: decision.request_kind || null, decision: decision.decision || null, decision_reason: decision.decision_reason || null, gross_edge_pct: decision.gross_edge_pct || null, threshold_pct: decision.threshold_pct || null, max_notional_eure: decision.max_notional_eure || null, strategy_armed: decision.strategy_armed ?? null, inventory_asset: decision.inventory_asset || null, eure_notional: decision.eure_notional || null, }; } function normalizeAlertList(alerts) { return (alerts || []).map(normalizeAlert).sort((left, right) => sortTimestamps( right.raised_at || right.first_raised_at || right.cleared_at, left.raised_at || left.first_raised_at || left.cleared_at, )); } function normalizeAlert(alert) { return { alert_code: alert.alert_code, status: alert.status, severity: alert.severity, reason: alert.reason, service_scope: alert.service_scope, pair: alert.pair || null, asset_id: alert.asset_id || null, tx_hash: alert.tx_hash || null, raised_at: alert.raised_at || null, first_raised_at: alert.first_raised_at || null, cleared_at: alert.cleared_at || null, last_evaluated_at: alert.last_evaluated_at || null, details: alert.details || {}, }; } function appendUniqueRecentQuote(quotes, nextQuote, limit) { const deduped = [nextQuote, ...quotes.filter((quote) => quote.quote_id !== nextQuote.quote_id)]; return deduped.slice(0, limit); } function normalizeLiveQuote(payload, event) { if (!payload?.quote_id) return null; return { quote_id: payload.quote_id, pair: payload.pair || `${payload.asset_in}->${payload.asset_out}`, asset_in: payload.asset_in || null, asset_out: payload.asset_out || null, request_kind: payload.request_kind || null, amount_in: payload.amount_in ?? null, amount_out: payload.amount_out ?? null, observed_at: event.observed_at || null, ingested_at: event.ingested_at || null, }; } function buildAlertKey(alert) { return [ alert.alert_code, alert.service_scope, alert.pair || '', alert.asset_id || '', alert.tx_hash || '', ].join('|'); } function highestAlertSeverity(alerts) { return (alerts || []).reduce((highest, alert) => { const currentRank = ALERT_SEVERITY_ORDER[highest] || 0; const nextRank = ALERT_SEVERITY_ORDER[alert.severity] || 0; return nextRank > currentRank ? alert.severity : highest; }, null); } function computeCurrentPortfolioValue({ inventory, marketPrice, btcAsset, eureAsset }) { if (!inventory || !marketPrice || !btcAsset || !eureAsset) return null; const btcUnits = String(inventory.spendable?.[btcAsset.assetId] || '0'); const eureUnits = String(inventory.spendable?.[eureAsset.assetId] || '0'); const btcScaled = unitsToScaledDecimal(btcUnits, btcAsset.decimals); const eureScaled = unitsToScaledDecimal(eureUnits, eureAsset.decimals); const priceScaled = parseScaledDecimal(marketPrice.eure_per_btc || marketPrice.eur_per_btc || '0'); const total = eureScaled + multiplyScaled(btcScaled, priceScaled); return formatScaledDecimal(total); } function valueAssetInEur({ asset, units, marketPrice }) { if (!asset) return null; if (asset.symbol === 'EURe') { return formatUnits(units || '0', asset.decimals); } if (!marketPrice || asset.symbol !== 'BTC') return null; const scaledUnits = unitsToScaledDecimal(units || '0', asset.decimals); const priceScaled = parseScaledDecimal(marketPrice.eure_per_btc || marketPrice.eur_per_btc || '0'); return formatScaledDecimal(multiplyScaled(scaledUnits, priceScaled)); } function formatDecimalDifference(left, right) { return formatScaledDecimal(parseScaledDecimal(left) - parseScaledDecimal(right)); } function unitsToScaledDecimal(units, decimals) { return BigInt(String(units || '0')) * 10n ** BigInt(DECIMAL_SCALE - decimals); } function parseScaledDecimal(value) { const normalized = String(value ?? '0').trim(); const negative = normalized.startsWith('-'); const unsigned = normalized.replace(/^[+-]/, ''); const [wholePart, fractionalPart = ''] = unsigned.split('.'); const whole = BigInt(wholePart || '0'); const fractional = BigInt( (fractionalPart.padEnd(DECIMAL_SCALE, '0')).slice(0, DECIMAL_SCALE) || '0', ); const scaled = (whole * DECIMAL_FACTOR) + fractional; return negative ? -scaled : scaled; } function multiplyScaled(left, right) { return (left * right) / DECIMAL_FACTOR; } function formatScaledDecimal(value) { const negative = value < 0n; const absolute = negative ? -value : value; const whole = absolute / DECIMAL_FACTOR; const fractional = absolute % DECIMAL_FACTOR; if (fractional === 0n) { return `${negative ? '-' : ''}${whole}`; } const fractionalText = fractional .toString() .padStart(DECIMAL_SCALE, '0') .replace(/0+$/, ''); return `${negative ? '-' : ''}${whole}.${fractionalText}`; } function formatUnits(units, decimals) { const numeric = unitsToNumber(units, decimals); if (!Number.isFinite(numeric)) return '0'; if (Math.abs(numeric) >= 1000) return numeric.toLocaleString('en-US', { maximumFractionDigits: 8 }); return numeric.toLocaleString('en-US', { maximumFractionDigits: 8 }); } function ageMs(value) { const parsed = Date.parse(value || ''); if (!Number.isFinite(parsed)) return null; return Math.max(0, Date.now() - parsed); } function sortTimestamps(left, right) { return timestampValue(left) - timestampValue(right); } function timestampValue(value) { const parsed = Date.parse(value || ''); return Number.isFinite(parsed) ? parsed : -Infinity; }