import { unitsToNumber } from './assets.mjs'; import { bridgeDepositObservedAt } from './bridge-assets.mjs'; import { summarizeFundingObservations } from './funding-observations.mjs'; import { resolveDashboardRequestAuth } from './operator-dashboard-auth.mjs'; import { TERMINAL_SETTLEMENT_ATTRIBUTION_STATUSES } from './quote-outcomes.mjs'; import { inferServiceFreshnessTimestamp as inferRuntimeFreshnessTimestamp } from './runtime-health.mjs'; export const DASHBOARD_LIVE_QUOTE_LIMIT = 10; export const DASHBOARD_LIVE_LIFECYCLE_LIMIT = 20; 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: 'operator-dashboard', action: 'import-supported-assets', method: 'POST', path: '/internal/import-supported-assets', label: 'Import Assets', description: 'Fetch and store the current 1Click supported token catalog.', page: 'strategy', risk_class: 'safe', }, { service: 'operator-dashboard', action: 'update-pair-edge', method: 'POST', path: '/internal/update-pair-edge', label: 'Update Edge', description: 'Create a new active strategy config version for a pair.', page: 'strategy', risk_class: 'safe', }, { service: 'operator-dashboard', action: 'enable-observe-only-pair', method: 'POST', path: '/internal/enable-observe-only-pair', label: 'Enable Observe-Only', description: 'Approve a directed pair for observation without enabling trading.', page: 'strategy', risk_class: 'safe', }, { service: 'operator-dashboard', action: 'set-pair-mode', method: 'POST', path: '/internal/set-pair-mode', label: 'Set Pair Mode', description: 'Activate a directed pair mode from durable DB config. Trading still requires valid strategy and price route state.', page: 'strategy', risk_class: 'live_funds', }, { service: 'operator-dashboard', action: 'pause-pair', method: 'POST', path: '/internal/pause-pair', label: 'Pause Pair', description: 'Disable a directed pair in durable DB config without deleting historical strategy versions.', page: 'strategy', risk_class: 'safe', }, { service: 'trade-executor', action: 'intent-request-preflight', method: 'POST', path: '/intent-request/preflight', label: 'Preflight BTC Request', description: 'Ask solvers for an EURe-to-BTC request quote without submitting live funds.', page: 'funds', risk_class: 'safe', }, { service: 'trade-executor', action: 'intent-request-submit', method: 'POST', path: '/intent-request/submit', label: 'Submit BTC Request', description: 'Submit a previously drafted EURe-to-BTC request. Relay acceptance is not settlement.', page: 'funds', risk_class: 'live_funds', }, { service: 'trade-executor', action: 'intent-request-refresh-outcomes', method: 'POST', path: '/intent-request/refresh-outcomes', label: 'Refresh Request Outcomes', description: 'Recompute own-request settlement attribution from durable inventory snapshots.', 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: 'arm', method: 'POST', path: '/arm', label: 'Arm Executor', description: 'Persistently arm trade-executor so strategy-approved decisions can submit.', page: 'system', risk_class: 'safe', }, { service: 'trade-executor', action: 'pause', method: 'POST', path: '/pause', label: 'Pause Executor Intake', description: 'Pause trade-executor command consumption without changing armed state.', page: 'system', risk_class: 'safe', }, { service: 'trade-executor', action: 'resume', method: 'POST', path: '/resume', label: 'Resume Executor Intake', description: 'Resume trade-executor command consumption without changing armed state.', 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 Sentinel', description: 'Pause background observation without changing trade arming state.', page: 'system', risk_class: 'safe', }, { service: 'ops-sentinel', action: 'resume', method: 'POST', path: '/resume', label: 'Resume Sentinel', description: 'Resume background observation.', 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'], ['operator-dashboard', 'Operator Dashboard', 'operatorDashboardControlBaseUrl'], ]; 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 buildDashboardControlErrorResponse(error, { control = null } = {}) { const name = String(error?.name || 'Error'); const message = String(error?.message || 'Control request failed.'); const timedOut = name === 'TimeoutError' || /timeout|aborted/i.test(message); return { statusCode: timedOut ? 504 : 502, payload: { ok: false, error: timedOut ? 'control_timeout' : 'control_failed', reason: message, control, }, }; } export function resolveDashboardControlTimeoutMs({ control, config } = {}) { const baseTimeoutMs = Number(config?.operatorDashboardUpstreamTimeoutMs || 3_000); if (control?.service !== 'trade-executor') return baseTimeoutMs; if (control.action === 'intent-request-preflight') { return Math.max(baseTimeoutMs, Number(config?.intentRequestQuoteTimeoutMs || 10_000) + 2_000); } if (control.action === 'intent-request-submit') { return Math.max( baseTimeoutMs, Number(config?.intentRequestPublishTimeoutMs || 10_000) + Number(config?.intentRequestStatusTimeoutMs || 10_000) + 5_000, ); } if (control.action === 'intent-request-refresh-outcomes') { return Math.max(baseTimeoutMs, Number(config?.intentRequestStatusTimeoutMs || 10_000) + 5_000); } return baseTimeoutMs; } export function listDashboardServices(config) { return SERVICE_DEFINITIONS.map(([service, label, configKey]) => ({ service, label, base_url: config[configKey], })); } export function createDashboardLiveState({ config, recentQuotes = [], recentTradeDecisions = [], recentExecuteTradeCommands = [], recentExecutionResults = [], recentQuoteOutcomes = [], latestMarketPrice = null, latestInventory = null, recentSubmissionCount = 0, lastSubmissionAt = null, activeAlerts = [], nearIntentsStatus = null, } = {}) { const state = { config, active_pair: config.activePair, btc_asset: config.tradingBtc, btc_assets: config.tradingBtcAssets || [config.tradingBtc], eure_asset: config.tradingEure, quote_limit: config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT, lifecycle_limit: config.operatorDashboardLifecycleLimit || DASHBOARD_LIVE_LIFECYCLE_LIMIT, recent_quotes: recentQuotes.slice(0, config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT), recent_trade_decisions: recentTradeDecisions.slice(0, config.operatorDashboardLifecycleLimit || DASHBOARD_LIVE_LIFECYCLE_LIMIT), recent_execute_trade_commands: recentExecuteTradeCommands.slice(0, config.operatorDashboardLifecycleLimit || DASHBOARD_LIVE_LIFECYCLE_LIMIT), recent_execution_results: recentExecutionResults.slice(0, config.operatorDashboardLifecycleLimit || DASHBOARD_LIVE_LIFECYCLE_LIMIT), recent_quote_outcomes: recentQuoteOutcomes.slice(0, config.operatorDashboardLifecycleLimit || DASHBOARD_LIVE_LIFECYCLE_LIMIT), latest_market_price: latestMarketPrice?.payload || latestMarketPrice || null, latest_inventory: latestInventory?.payload || latestInventory || null, recent_submission_count: Number(recentSubmissionCount || 0), last_submission_at: lastSubmissionAt || null, near_intents_status: nearIntentsStatus, active_alerts: new Map(), }; for (const alert of activeAlerts) { if (!alert) continue; state.active_alerts.set(buildAlertKey(alert), alert); } return state; } export function buildLiveQuoteLifecycleRows(state, { flashQuoteId = null, flashAt = null } = {}) { const rows = deriveQuoteLifecycleRows({ recentQuotes: state.recent_quotes, recentTradeDecisions: state.recent_trade_decisions, recentExecuteTradeCommands: state.recent_execute_trade_commands, recentExecutionResults: state.recent_execution_results, recentQuoteOutcomes: state.recent_quote_outcomes, limit: state.lifecycle_limit, }).map((row) => enrichLifecycleRowForUi({ config: state.config, row })); if (!flashQuoteId) return rows; const highlightedAt = flashAt || new Date().toISOString(); return rows.map((row) => ( row.quote_id === flashQuoteId ? { ...row, live_flash_at: highlightedAt } : row )); } export function applyDashboardLiveEvent(state, { topic, event }) { if (!event?.payload) return []; switch (normalizeDashboardLiveTopic(state, 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, }, buildQuoteLifecycleUpdate(state, { flashQuoteId: quote.quote_id }), ]; } case 'decision.trade_decision': { const decision = normalizeLiveDecision(event.payload, event); if (!decision) return []; state.recent_trade_decisions = appendUniqueRecentEvent( state.recent_trade_decisions, decision, state.lifecycle_limit, (entry) => livePayloadKey(entry, ['decision_id', 'quote_id']), ); return [buildQuoteLifecycleUpdate(state, { flashQuoteId: decision.payload?.quote_id })]; } case 'cmd.execute_trade': { const command = normalizeLiveCommand(event.payload, event); if (!command) return []; state.recent_execute_trade_commands = appendUniqueRecentEvent( state.recent_execute_trade_commands, command, state.lifecycle_limit, (entry) => livePayloadKey(entry, ['command_id', 'decision_id', 'quote_id']), ); return [buildQuoteLifecycleUpdate(state, { flashQuoteId: command.payload?.quote_id })]; } 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': { return []; } case 'ops.environment_status': { state.near_intents_status = event.payload; return [ { type: 'status_bar.updated', status_bar: buildLiveStatusBar(state), }, { type: 'environment_status.updated', environment_status: { observed_at: event.observed_at || event.payload.observed_at || null, ingested_at: event.ingested_at || null, payload: event.payload, }, }, ]; } case 'exec.trade_result': { const execution = normalizeLiveExecutionResult(event.payload, event); if (!execution) return []; state.recent_execution_results = appendUniqueRecentEvent( state.recent_execution_results, execution, state.lifecycle_limit, (entry) => livePayloadKey(entry, ['command_id', 'decision_id', 'quote_id', 'result_at']), ); const updates = []; if (event.payload.status === 'submitted') { state.recent_submission_count += 1; state.last_submission_at = event.observed_at || event.ingested_at || new Date().toISOString(); updates.push({ type: 'status_bar.updated', status_bar: buildLiveStatusBar(state), }); } updates.push(buildQuoteLifecycleUpdate(state, { flashQuoteId: execution.quote_id })); return updates; } default: return []; } } export function buildDashboardBootstrap({ config, auth, portfolioMetric, inventorySnapshot, marketPrice, recentQuotes, submissionPage, submissionSummary, fundingObservations, recentDepositStatuses, recentTradeDecisions, recentExecuteTradeCommands, recentExecutionResults, recentQuoteOutcomes = [], recentIntentRequests = [], recentAlertTransitions, recentEnvironmentStatuses = [], assetCatalog = null, pairConfig = null, serviceSnapshots, nearIntentsStatus = null, sourceErrors = [], } = {}) { const servicesByName = Object.fromEntries( (serviceSnapshots || []).map((snapshot) => [snapshot.service, snapshot]), ); const activeAlerts = normalizeAlertList( servicesByName['ops-sentinel']?.state?.active_alerts || [], ); const recentAlerts = summarizeRecentAlertTransitions(normalizeAlertList( servicesByName['ops-sentinel']?.state?.recent_transitions || recentAlertTransitions?.map((entry) => entry.payload) || [], )); const profitability = buildProfitabilitySummary({ metric: portfolioMetric, submissionSummary, }); const balances = buildBalanceSummary({ inventorySnapshot, marketPrice, config, portfolioMetric, }); const funding = buildFundingSummary({ config, fundingObservations, recentDepositStatuses, liquidityState: servicesByName['liquidity-manager']?.state || {}, }); const normalizedSubmissionPage = normalizeSubmissionPage({ config, submissionPage, }); const environmentStatus = buildEnvironmentStatusHistory({ recentEnvironmentStatuses, currentStatus: nearIntentsStatus, }); const effectiveNearIntentsStatus = nearIntentsStatus || environmentStatus.current; return { session: auth, source_errors: sourceErrors, default_page: 'funds', status_bar: buildStatusBar({ config, profitability, inventorySnapshot, marketPrice, activeAlerts, servicesByName, nearIntentsStatus: effectiveNearIntentsStatus, }), funds: { profitability, balances, funding, recent_deposits: funding.credited_deposits, recent_withdrawals: buildRecentWithdrawals({ config, liquidityState: servicesByName['liquidity-manager']?.state || {}, }), recent_submission_terms: buildRecentSubmissionTerms({ config, submissions: normalizedSubmissionPage.items, }), recent_quotes: (recentQuotes || []).slice(0, config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT), intent_requests: buildIntentRequestSummary({ config, intentRequests: recentIntentRequests, executorState: servicesByName['trade-executor']?.state || {}, }), submission_ledger: normalizedSubmissionPage, controls: listDashboardControls({ page: 'funds' }), caveats: profitability.caveats, }, strategy: buildStrategySummary({ config, servicesByName, activeAlerts, assetCatalog, pairConfig, fundingHandles: funding.handles, recentQuotes, recentTradeDecisions, recentExecuteTradeCommands, recentExecutionResults, recentQuoteOutcomes, }), system: buildSystemSummary({ servicesByName, activeAlerts, recentAlerts, nearIntentsStatus: effectiveNearIntentsStatus, environmentStatus, }), }; } export function buildProfitabilitySummary({ metric, submissionSummary } = {}) { 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, portfolio_vs_simple_hold_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_submission_count: submissionSummary?.total ?? 0, last_submission_at: submissionSummary?.last_submission_at || null, caveats: [ 'Portfolio value and simple-hold comparison use durable inventory and reference prices.', 'This is not realized per-trade PnL; completed trades require linked outcome and settlement records.', ], }; 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.portfolio_vs_simple_hold_eure = formatDecimalDifference( summary.current_total_portfolio_value_eure, summary.simple_hold_value_eure, ); summary.trading_contribution_eure = null; } 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 { near_intents_upstream_status: state.near_intents_status?.status || null, near_intents_upstream_label: state.near_intents_status?.label || null, near_intents_upstream_reason: state.near_intents_status?.decisive_reason || null, near_intents_upstream_observed_at: state.near_intents_status?.observed_at || null, 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, btcAssets: state.btc_assets, eureAsset: state.eure_asset, }), active_alert_count: 0, highest_alert_severity: null, recent_submission_count: state.recent_submission_count, last_submission_at: state.last_submission_at, }; } function buildStatusBar({ config, profitability, inventorySnapshot, marketPrice, activeAlerts, servicesByName, nearIntentsStatus = null, }) { return { active_pair: config.activePair, near_intents_upstream_status: nearIntentsStatus?.status || null, near_intents_upstream_label: nearIntentsStatus?.label || null, near_intents_upstream_reason: nearIntentsStatus?.decisive_reason || null, near_intents_upstream_observed_at: nearIntentsStatus?.observed_at || null, 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: 0, highest_alert_severity: null, 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_submission_count: profitability.recent_submission_count, last_submission_at: profitability.last_submission_at, }; } function buildBalanceSummary({ inventorySnapshot, marketPrice, config, portfolioMetric = null }) { const inventory = inventorySnapshot?.payload || {}; const spendable = inventory.spendable || {}; const pendingInbound = inventory.pending_inbound || {}; const pendingOutbound = inventory.pending_outbound || {}; const balanceAssets = config.trackedAssets?.length ? config.trackedAssets : [...config.assetRegistry.values()]; const metricValuationsByAssetId = new Map( (portfolioMetric?.payload?.current_inventory?.valued_assets || []) .filter((asset) => asset?.asset_id) .map((asset) => [asset.asset_id, asset]), ); return { synced_at: inventory.synced_at || inventorySnapshot?.ingested_at || null, reconciliation_status: inventory.reconciliation_status || null, items: balanceAssets.map((asset) => { const spendableUnits = String(spendable[asset.assetId] || '0'); const pendingInboundUnits = String(pendingInbound[asset.assetId] || '0'); const pendingOutboundUnits = String(pendingOutbound[asset.assetId] || '0'); const metricValuation = metricValuationsByAssetId.get(asset.assetId); return { asset_id: asset.assetId, symbol: asset.symbol, label: asset.label || asset.symbol, role: asset.role || null, 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: metricValuation?.value_eure || valueAssetInEur({ asset, units: spendableUnits, marketPrice: marketPrice?.payload || marketPrice || null, }), eur_value_source: metricValuation?.valuation_source || 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]) => { const chainAssets = (config.trackedAssets || [...config.assetRegistry.values()]) .filter((asset) => asset.chain === chain); return { chain, asset_id: chainAssets.length === 1 ? chainAssets[0].assetId : null, asset_ids: chainAssets.map((asset) => asset.assetId), symbol: chainAssets.length === 1 ? chainAssets[0].symbol : chainAssets.map((asset) => asset.label || asset.symbol).join(', '), label: chainAssets.length === 1 ? (chainAssets[0].label || chainAssets[0].symbol) : `${chain} funding handle`, 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, asset_symbol: asset?.label || 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, asset_symbol: asset?.label || 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 buildIntentRequestSummary({ config, intentRequests = [], executorState = {} } = {}) { const defaultPair = config.defaultTakerPair || null; const strategyConfig = defaultPair?.strategyConfig || null; const usingDbPairConfig = Boolean(config.tradingConfigLoaded && strategyConfig); const sourceAsset = defaultPair?.assetIn || config.tradingEure; const destinationAsset = defaultPair?.assetOut || config.tradingBtc; return { defaults: { source_symbol: sourceAsset?.symbol || 'Source', destination_symbol: destinationAsset?.symbol || 'Destination', amount_eure: String(strategyConfig?.requestDefaultNotional ?? config.intentRequestDefaultAmountEure ?? 5), max_amount_eure: usingDbPairConfig ? strategyConfig.requestMaxNotional ?? null : String(config.intentRequestMaxAmountEure || 5), slippage_bps: Number(strategyConfig?.slippageBps ?? config.intentRequestDefaultSlippageBps ?? 200), max_slippage_bps: usingDbPairConfig ? strategyConfig.requestMaxSlippageBps ?? null : Number(config.intentRequestMaxSlippageBps ?? 200), }, executor_armed: executorState.armed ?? null, executor_paused: executorState.paused ?? null, request_creation_state: executorState.request_creation || null, items: (intentRequests || []).map((request) => normalizeIntentRequestForUi({ config, request })), caveat: 'Own request relay acceptance is not a completed trade. Completed requires durable EURe decrease and BTC increase evidence.', }; } function normalizeIntentRequestForUi({ config, request }) { const sourceAsset = config.assetRegistry.get(request.source_asset_id) || config.tradingEure; const destinationAsset = config.assetRegistry.get(request.destination_asset_id) || config.tradingBtc; return { ...request, source_amount: formatUnits(request.source_amount_units || '0', sourceAsset?.decimals || 0), expected_destination_amount: formatUnits( request.expected_destination_amount_units || '0', destinationAsset?.decimals || 0, ), min_destination_amount: formatUnits( request.min_destination_amount_units || '0', destinationAsset?.decimals || 0, ), quoted_destination_amount: request.quoted_destination_amount_units == null ? null : formatUnits(request.quoted_destination_amount_units || '0', destinationAsset?.decimals || 0), settlement_summary: buildSettlementSummary({ config, delta: request.attributed_inventory_delta, attributionStatus: request.attribution_status, attributionMethod: request.attribution_method, subject: 'request', }), }; } 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, asset_symbol: asset?.label || asset?.symbol || withdrawal.asset_id, chain: withdrawal.chain || null, amount_units: String(withdrawal.amount || '0'), amount_display: formatUnits(withdrawal.amount || '0', asset?.decimals || 0), amount: formatUnits(withdrawal.amount || '0', asset?.decimals || 0), status: withdrawal.status || null, address: withdrawal.address || null, destination_address: withdrawal.address || null, requested_at: withdrawal.submitted_at || withdrawal.noted_at || null, completed_at: withdrawal.status === 'COMPLETED' ? withdrawal.last_checked_at : null, submitted_at: withdrawal.submitted_at || null, last_checked_at: withdrawal.last_checked_at || null, noted_at: withdrawal.noted_at || null, }; }); } function buildRecentSubmissionTerms({ config, submissions }) { return (submissions || []).slice(0, 10).map((submission) => { const assetIn = config.assetRegistry.get(submission.asset_in); const assetOut = config.assetRegistry.get(submission.asset_out); return { observed_at: submission.observed_at, quote_id: submission.quote_id, request_kind: submission.request_kind, asset_in: submission.asset_in, asset_in_symbol: assetIn?.symbol || submission.asset_in, amount_in_units: submission.amount_in, amount_in: formatUnits(submission.amount_in || '0', assetIn?.decimals || 0), asset_out: submission.asset_out, asset_out_symbol: assetOut?.symbol || submission.asset_out, amount_out_units: submission.amount_out, amount_out: formatUnits(submission.amount_out || '0', assetOut?.decimals || 0), }; }); } function normalizeSubmissionPage({ config, submissionPage }) { return { ...submissionPage, items: (submissionPage?.items || []).map((trade) => normalizeTradeForUi({ config, trade, })), }; } const LIFECYCLE_TONE_BY_STATE = { observed: 'info', evaluated: 'healthy', command_emitted: 'info', rejected: 'warning', blocked: 'warning', failed: 'critical', submitted: 'healthy', awaiting_outcome: 'info', not_filled: 'warning', completed: 'healthy', }; const HUMAN_REASON_TEXT = { actionable: 'Strategy approved the quote.', below_edge_threshold: 'Below edge threshold.', duplicate_quote_id: 'Duplicate quote id.', executor_disarmed: 'Executor is disarmed.', executor_paused: 'Executor intake is paused.', inventory_unavailable: 'Inventory unavailable.', pending_deposit_not_credited: 'Funding is not credited yet.', quote_expired: 'Quote expired.', quote_response_ack: 'Quote response acknowledged by the relay.', quote_response_ok: 'Quote response accepted by the relay.', awaiting_outcome: 'No durable venue outcome is recorded yet.', deadline_elapsed_without_settlement: 'No matching inventory delta was observed after the quote-response deadline.', matched_inventory_delta: 'Matched to an observed inventory delta. Attribution is heuristic unless the source says linked settlement.', ambiguous_inventory_delta_match: 'Inventory movement matched more than one quote candidate.', reason_unknown: 'Reason not recorded.', stale_reference_price: 'Reference price is stale.', strategy_approved: 'Strategy approved the quote.', strategy_disarmed: 'Strategy is disarmed.', submission_failed: 'Submission failed.', unsupported_pair: 'Unsupported pair.', }; const COMPLETED_OUTCOME_STATUSES = new Set(['completed', 'filled', 'settled', 'finalized']); const NOT_FILLED_OUTCOME_STATUSES = new Set(['expired', 'not_filled', 'cancelled']); export function deriveQuoteLifecycleRows({ recentQuotes = [], recentTradeDecisions = [], recentExecuteTradeCommands = [], recentExecutionResults = [], recentQuoteOutcomes = [], limit = 20, } = {}) { const rowsByKey = new Map(); for (const quote of recentQuotes || []) { const normalizedQuote = normalizeLifecycleQuote(quote); const row = ensureLifecycleRow(rowsByKey, normalizedQuote?.quote_id || `quote:${normalizedQuote?.observed_at || normalizedQuote?.ingested_at || rowsByKey.size}`); mergeLifecycleEvidence(row, { quote_id: normalizedQuote?.quote_id || null, pair: normalizedQuote?.pair || null, request_kind: normalizedQuote?.request_kind || null, asset_in: normalizedQuote?.asset_in || null, asset_out: normalizedQuote?.asset_out || null, amount_in: normalizedQuote?.amount_in || null, amount_out: normalizedQuote?.amount_out || null, quote: normalizedQuote, quote_observed_at: normalizedQuote?.observed_at || normalizedQuote?.ingested_at || null, }); } for (const decisionEntry of recentTradeDecisions || []) { const decision = normalizeDecision({ ...(decisionEntry?.payload || decisionEntry || {}), decision_at: decisionEntry?.payload?.decision_at || decisionEntry?.decision_at || decisionEntry?.observed_at || decisionEntry?.ingested_at || null, }); if (!decision) continue; const row = ensureLifecycleRow(rowsByKey, decision.quote_id || decision.decision_id || `decision:${decision.decision_at || rowsByKey.size}`); mergeLifecycleEvidence(row, { quote_id: decision.quote_id, decision_id: decision.decision_id, pair: decision.pair, pair_id: decision.pair_id, pair_config_id: decision.pair_config_id, pair_config_version: decision.pair_config_version, edge_bps: decision.edge_bps, direction: decision.direction, request_kind: decision.request_kind, gross_edge_pct: decision.gross_edge_pct, eure_notional: decision.eure_notional, decision, decision_at: decision.decision_at || null, }); } for (const commandEntry of recentExecuteTradeCommands || []) { const command = normalizeCommand({ ...(commandEntry?.payload || commandEntry || {}), command_at: commandEntry?.command_at || commandEntry?.observed_at || commandEntry?.ingested_at || null, }); if (!command) continue; const row = ensureLifecycleRow(rowsByKey, command.quote_id || command.decision_id || command.command_id || `command:${command.command_at || rowsByKey.size}`); mergeLifecycleEvidence(row, { quote_id: command.quote_id, decision_id: command.decision_id, command_id: command.command_id, pair: command.pair, pair_id: command.pair_id, pair_config_id: command.pair_config_id, pair_config_version: command.pair_config_version, edge_bps: command.edge_bps, direction: command.direction, request_kind: command.request_kind, asset_in: command.asset_in || null, asset_out: command.asset_out || null, amount_in: command.amount_in || null, amount_out: command.amount_out || null, command, command_at: command.command_at || null, }); } for (const execution of recentExecutionResults || []) { const row = ensureLifecycleRow(rowsByKey, execution?.quote_id || execution?.decision_id || execution?.command_id || `execution:${execution?.result_at || rowsByKey.size}`); mergeLifecycleEvidence(row, { quote_id: execution?.quote_id || null, decision_id: execution?.decision_id || null, command_id: execution?.command_id || null, pair: execution?.pair || null, execution, execution_result_at: execution?.result_at || null, }); } for (const outcome of recentQuoteOutcomes || []) { const row = ensureLifecycleRow(rowsByKey, outcome?.quote_id || outcome?.decision_id || outcome?.command_id || `outcome:${outcome?.outcome_observed_at || rowsByKey.size}`); mergeLifecycleEvidence(row, { quote_id: outcome?.quote_id || null, decision_id: outcome?.decision_id || null, command_id: outcome?.command_id || null, pair: outcome?.pair || null, direction: outcome?.direction || null, request_kind: outcome?.request_kind || null, gross_edge_pct: outcome?.gross_edge_pct || null, eure_notional: outcome?.eure_notional || null, outcome, command_at: outcome?.command_at || null, execution_result_at: outcome?.submitted_at || null, outcome_observed_at: outcome?.outcome_observed_at || outcome?.submitted_at || null, }); } const finalized = [...rowsByKey.values()] .map((row) => finalizeLifecycleRow(row)) .sort((left, right) => sortTimestamps(right.quote_activity_at, left.quote_activity_at)); return limit == null ? finalized : finalized.slice(0, limit); } function ensureLifecycleRow(rowsByKey, key) { if (!rowsByKey.has(key)) { rowsByKey.set(key, { quote_id: null, decision_id: null, command_id: null, pair: null, pair_id: null, pair_config_id: null, pair_config_version: null, edge_bps: null, direction: null, request_kind: null, gross_edge_pct: null, eure_notional: null, quote_observed_at: null, decision_at: null, asset_in: null, asset_out: null, amount_in: null, amount_out: null, command_at: null, execution_result_at: null, outcome_observed_at: null, quote: null, decision: null, command: null, execution: null, outcome: null, }); } return rowsByKey.get(key); } function mergeLifecycleEvidence(row, next) { for (const [key, value] of Object.entries(next || {})) { if (value != null && row[key] == null) { row[key] = value; } } if (next?.quote) row.quote = next.quote; if (next?.decision) row.decision = next.decision; if (next?.command) row.command = next.command; if (next?.execution) row.execution = next.execution; if (next?.outcome) row.outcome = next.outcome; } function finalizeLifecycleRow(row) { const decision = row.decision || null; const execution = row.execution || null; const outcome = row.outcome || null; const outcomeStatus = normalizeLifecycleToken( outcome?.outcome_status || execution?.outcome_status || execution?.outcome_reason || null, ); let lifecycle_state = 'observed'; let lifecycle_label = 'Observed'; let reason_code = 'reason_unknown'; let reason_text = 'Strategy evaluation not recorded yet.'; if (outcomeStatus && COMPLETED_OUTCOME_STATUSES.has(outcomeStatus)) { lifecycle_state = 'completed'; lifecycle_label = 'Completed'; reason_code = normalizeLifecycleToken( outcome?.outcome_reason || execution?.outcome_reason || execution?.result_code || 'completed', ); reason_text = buildCompletedOutcomeText({ outcome, reasonCode: reason_code }); } else if (outcomeStatus && NOT_FILLED_OUTCOME_STATUSES.has(outcomeStatus)) { lifecycle_state = 'not_filled'; lifecycle_label = 'Not filled'; reason_code = normalizeLifecycleToken( outcome?.outcome_reason || execution?.outcome_reason || execution?.result_code || outcomeStatus, ); reason_text = buildNotFilledText({ outcome, reasonCode: reason_code }); } else if (outcomeStatus === 'awaiting_outcome') { lifecycle_state = 'awaiting_outcome'; lifecycle_label = 'Awaiting outcome'; reason_code = normalizeLifecycleToken(outcome?.outcome_reason || 'awaiting_outcome'); reason_text = humanizeReasonCode(reason_code, 'No durable venue outcome is recorded yet.'); } else if (execution?.status === 'submitted') { lifecycle_state = 'submitted'; lifecycle_label = 'Submitted'; reason_code = normalizeLifecycleToken(execution?.result_code || 'awaiting_outcome'); reason_text = `${humanizeReasonCode(reason_code, 'Submitted to the relay.')} No durable venue outcome is recorded yet.`; } else if (execution?.status === 'failed') { lifecycle_state = 'failed'; lifecycle_label = 'Submission failed'; reason_code = normalizeLifecycleToken(execution?.result_code || 'submission_failed'); reason_text = buildExecutionFailureText(execution, reason_code); } else if (execution?.status === 'rejected') { lifecycle_state = 'blocked'; lifecycle_label = 'Blocked before submit'; reason_code = normalizeLifecycleToken(execution?.result_code || 'reason_unknown'); reason_text = buildExecutorBlockText(execution, reason_code); } else if (row.command_id || row.command_at) { lifecycle_state = 'command_emitted'; lifecycle_label = 'Awaiting executor'; reason_code = 'awaiting_executor'; reason_text = 'Execute command recorded, but no executor result is stored yet.'; } else if (decision?.decision === 'rejected') { lifecycle_state = 'rejected'; lifecycle_label = 'Rejected by strategy'; reason_code = normalizeLifecycleToken(decision?.decision_reason || 'reason_unknown'); reason_text = humanizeReasonCode(reason_code, 'Strategy rejected the quote.'); } else if (decision?.decision) { lifecycle_state = 'evaluated'; lifecycle_label = 'Approved by strategy'; reason_code = normalizeLifecycleToken(decision?.decision_reason || 'strategy_approved'); reason_text = 'Strategy approved the quote, but no durable execute command is recorded yet.'; } return { ...row, lifecycle_state, lifecycle_label, lifecycle_tone: LIFECYCLE_TONE_BY_STATE[lifecycle_state] || 'unknown', reason_code, reason_text, latest_stage_at: row.outcome_observed_at || row.execution_result_at || row.command_at || row.decision_at || row.quote_observed_at || null, quote_activity_at: row.quote_observed_at || row.decision_at || row.command_at || row.execution_result_at || row.outcome_observed_at || null, stage_details: { quote_observed_at: row.quote_observed_at, decision_at: row.decision_at, command_at: row.command_at, execution_result_at: row.execution_result_at, strategy_decision: decision?.decision || null, strategy_reason_code: decision?.decision_reason || null, execution_status: execution?.status || null, execution_result_code: execution?.result_code || null, execution_outcome_status: execution?.outcome_status || null, durable_outcome_status: outcome?.outcome_status || null, durable_outcome_source: outcome?.outcome_source || null, attribution_status: outcome?.attribution_status || null, attribution_method: outcome?.attribution_method || null, }, outcome_source: outcome?.outcome_source || null, outcome_status: outcome?.outcome_status || execution?.outcome_status || null, attribution_status: outcome?.attribution_status || execution?.attribution_status || null, attribution_method: outcome?.attribution_method || execution?.attribution_method || null, attributed_inventory_delta: outcome?.attributed_inventory_delta || execution?.attributed_inventory_delta || null, has_settlement_evidence: hasSettlementEvidence(outcome || execution), }; } function buildCompletedOutcomeText({ outcome, reasonCode }) { const base = humanizeReasonCode(reasonCode, 'Completed.'); if (!outcome?.attribution_status) return `${base} Settlement attribution is not stored.`; if (outcome.attribution_status === 'heuristic_match') { return `${base} Matched to inventory movement by exact asset-unit delta; venue terminal status is not stored.`; } return base; } function buildNotFilledText({ outcome, reasonCode }) { const base = humanizeReasonCode(reasonCode, 'Not filled.'); const uncertainty = outcome?.evidence?.uncertainty; return uncertainty ? `${base} ${uncertainty}` : base; } function hasSettlementEvidence(outcome) { return Boolean( outcome?.attributed_inventory_delta && TERMINAL_SETTLEMENT_ATTRIBUTION_STATUSES.has(outcome.attribution_status), ); } function buildExecutionFailureText(execution, reasonCode) { const base = humanizeReasonCode(reasonCode, 'Submission failed.'); if (execution?.error_message) return `${base} ${execution.error_message}`; if (execution?.note) return `${base} ${execution.note}`; return base; } function buildExecutorBlockText(execution, reasonCode) { if (execution?.note) return execution.note; return humanizeReasonCode(reasonCode, 'Executor blocked the submission.'); } function humanizeReasonCode(code, fallback = 'Reason not recorded.') { const normalized = normalizeLifecycleToken(code || ''); if (!normalized) return fallback; return HUMAN_REASON_TEXT[normalized] || normalized.replaceAll('_', ' '); } function normalizeLifecycleToken(value) { return String(value || '') .trim() .toLowerCase() .replace(/[\s-]+/g, '_'); } function normalizeLifecycleQuote(quote) { if (!quote) return null; return { quote_id: quote.quote_id || null, pair: quote.pair || null, asset_in: quote.asset_in || null, asset_out: quote.asset_out || null, request_kind: quote.request_kind || null, amount_in: quote.amount_in ?? null, amount_out: quote.amount_out ?? null, min_deadline_ms: quote.min_deadline_ms ?? null, observed_at: quote.observed_at || null, ingested_at: quote.ingested_at || null, }; } function normalizeCommand(command) { if (!command) return null; return { command_id: command.command_id || null, decision_id: command.decision_id || null, execution_key: command.execution_key || null, quote_id: command.quote_id || null, pair: command.pair || null, pair_id: command.pair_id || null, pair_config_id: command.pair_config_id || null, pair_config_version: command.pair_config_version || null, edge_bps: command.edge_bps || null, direction: command.direction || null, request_kind: command.request_kind || null, asset_in: command.asset_in || null, asset_out: command.asset_out || null, amount_in: command.amount_in ?? null, amount_out: command.amount_out ?? null, command_at: command.command_at || command.observed_at || command.ingested_at || null, }; } function buildStrategySummary({ config, servicesByName, activeAlerts, assetCatalog = null, pairConfig = null, fundingHandles = [], recentQuotes = [], recentTradeDecisions = [], recentExecuteTradeCommands = [], recentExecutionResults = [], recentQuoteOutcomes = [], }) { 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, }); const allLifecycleRows = deriveQuoteLifecycleRows({ recentQuotes, recentTradeDecisions, recentExecuteTradeCommands, recentExecutionResults, recentQuoteOutcomes, limit: null, }).map((row) => enrichLifecycleRowForUi({ config, row })); const lifecycleRows = allLifecycleRows.slice(0, 20); const tradeFunnel = buildTradeFunnelSummary(allLifecycleRows); return { strategy_state: { armed: strategyState.armed ?? null, paused: strategyState.paused ?? null, threshold_pct: strategyState.threshold_pct ?? firstActivePairConfig(pairConfig)?.edge_pct ?? null, max_notional_eure: strategyState.max_notional_eure ?? firstActivePairConfig(pairConfig)?.max_notional ?? null, latest_decision: latestDecision?.decision_id ? latestDecision : null, recent_decisions: recentDecisions.length ? recentDecisions : [...durableDecisionsById.values()].slice(0, 20), recent_lifecycle_rows: lifecycleRows, trade_funnel: tradeFunnel, skipped_counts: strategyState.skipped_counts || {}, durable_control_state: strategyState.durable_control_state || null, trading_config: strategyState.trading_config || null, }, asset_catalog: attachDepositHandlesToAssetCatalog( assetCatalog || buildFallbackAssetCatalog(config), fundingHandles, ), pair_config: pairConfig || buildFallbackPairConfig(config), executor_state: { armed: executorState.armed ?? null, paused: executorState.paused ?? null, draining: executorState.draining ?? null, in_flight_count: executorState.in_flight_count ?? 0, submitted_count: executorState.submitted_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: [], omitted_controls: [ 'Strategy arm and disarm are intentionally absent in this turn.', 'Executor drain remains intentionally absent in this turn.', 'Live withdrawal submission is intentionally absent in this turn.', ], }; } function attachDepositHandlesToAssetCatalog(assetCatalog, fundingHandles = []) { const handlesByAssetId = new Map(); const handlesByChain = new Map(); for (const handle of fundingHandles || []) { if (!handle) continue; if (handle.chain) handlesByChain.set(handle.chain, handle); if (handle.asset_id) handlesByAssetId.set(handle.asset_id, handle); for (const assetId of handle.asset_ids || []) { handlesByAssetId.set(assetId, handle); } } return { ...(assetCatalog || {}), items: (assetCatalog?.items || []).map((asset) => { const assetId = asset.asset_id || asset.assetId; const chain = asset.chain || asset.blockchain || null; const handle = handlesByAssetId.get(assetId) || handlesByChain.get(chain) || null; return { ...asset, depositAddress: handle?.address || null, deposit_address: handle?.address || null, depositChain: handle?.chain || chain, deposit_chain: handle?.chain || chain, depositMemo: handle?.memo || null, deposit_memo: handle?.memo || null, depositRefreshedAt: handle?.refreshed_at || null, deposit_refreshed_at: handle?.refreshed_at || null, }; }), }; } function buildTradeFunnelSummary(lifecycleRows = []) { const counts = { observed: 0, rejected: 0, blocked: 0, submitted: 0, awaiting_outcome: 0, failed: 0, not_filled: 0, completed: 0, }; const successfulTrades = []; const unresolvedSubmissions = []; const noTradeRows = []; for (const row of lifecycleRows || []) { if (Object.hasOwn(counts, row.lifecycle_state)) { counts[row.lifecycle_state] += 1; } if (row.lifecycle_state === 'completed' && row.has_settlement_evidence) { successfulTrades.push(row); } else if (['submitted', 'awaiting_outcome'].includes(row.lifecycle_state)) { unresolvedSubmissions.push(row); noTradeRows.push(row); } else if (['observed', 'evaluated', 'command_emitted', 'rejected', 'blocked', 'failed', 'not_filled'].includes(row.lifecycle_state)) { noTradeRows.push(row); } } const grossEdgeEstimate = summarizeGrossEdgeEstimate(successfulTrades); return { successful_trade_count: successfulTrades.length, successful_trade_gross_edge_estimate_eure: grossEdgeEstimate.total_eure, successful_trade_gross_edge_estimate_count: grossEdgeEstimate.count, unresolved_submission_count: unresolvedSubmissions.length, no_trade_count: noTradeRows.length, successful_trades: successfulTrades, unresolved_submissions: unresolvedSubmissions.slice(0, 20), no_trade_rows: [], counts, caveat: successfulTrades.length > 0 ? 'Successful trades require durable terminal outcome evidence.' : 'No quote currently has linked terminal outcome and settled inventory evidence, so there are no successful trades to show yet.', }; } function firstActivePairConfig(pairConfig) { const pair = pairConfig?.pairs?.find((entry) => entry.strategyConfig || entry.strategy_config); const strategyConfig = pair?.strategyConfig || pair?.strategy_config || null; if (!strategyConfig) return null; return { edge_pct: strategyConfig.edge_bps == null ? null : String(Number(strategyConfig.edge_bps) / 100), max_notional: strategyConfig.max_notional == null ? null : String(strategyConfig.max_notional), }; } function buildFallbackAssetCatalog(config) { const items = [...(config.assetRegistry?.values?.() || [])].map((asset) => ({ asset_id: asset.assetId, symbol: asset.symbol, label: asset.label || asset.symbol, decimals: asset.decimals, blockchain: asset.blockchain || asset.chain || null, chain: asset.chain || asset.blockchain || null, supported: asset.supported ?? null, retired_at: asset.retiredAt || null, enabled_for_inventory: asset.enabledForInventory ?? true, })); return { latest_import: null, counts: { known: items.length, supported: items.filter((asset) => asset.supported === true).length, retired: items.filter((asset) => asset.retired_at).length, inventory_enabled: items.filter((asset) => asset.enabled_for_inventory !== false).length, }, items, }; } function buildFallbackPairConfig(config) { return { ok: false, block_reason: 'pair_config_unavailable', loaded_at: null, pairs: config.activePair ? [{ pair_id: config.activePair, key: config.activePair, mode: 'legacy', status: 'legacy', enabled: false, canTrade: false, blockReason: 'pair_config_unavailable', }] : [], }; } function summarizeGrossEdgeEstimate(rows = []) { let total = 0n; let count = 0; for (const row of rows || []) { const value = row?.gross_edge_value_eure || estimateGrossEdgeValueEure(row); if (value == null) continue; total += parseScaledDecimal(value); count += 1; } return { count, total_eure: count > 0 ? formatScaledDecimal(total) : null, }; } function buildEnvironmentStatusHistory({ recentEnvironmentStatuses = [], currentStatus = null } = {}) { const recentChanges = (recentEnvironmentStatuses || []).map((entry) => ({ observed_at: entry.observed_at || entry.payload?.observed_at || null, ingested_at: entry.ingested_at || null, payload: entry.payload || entry, })); const latestDurable = recentChanges[0]?.payload || null; const current = currentStatus || latestDurable; return { current, recent_changes: recentChanges, latest_durable_change_at: recentChanges[0]?.payload?.changed_at || recentChanges[0]?.observed_at || recentChanges[0]?.ingested_at || null, change_count: recentChanges.length, }; } function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts, nearIntentsStatus = null, environmentStatus = { current: null, recent_changes: [] }, }) { const historyWriterState = servicesByName['history-writer']?.state || {}; void activeAlerts; void recentAlerts; return { service_health: Object.values(servicesByName).map((snapshot) => ( summarizeServiceSnapshot(snapshot, { authoritativeHealth: null, activeAlerts: [], nearIntentsStatus, }) )), alerts: { active: [], recent: [], }, environment_status: environmentStatus, 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_environment_status_write_at: historyWriterState.last_environment_status_write_at || null, last_environment_status_seen_at: historyWriterState.last_environment_status_seen_at || null, last_environment_status_duplicate_at: historyWriterState.last_environment_status_duplicate_at || null, last_metrics_at: historyWriterState.last_metrics_at || null, last_quote_outcomes_at: historyWriterState.last_quote_outcomes_at || null, latest_portfolio_metrics: historyWriterState.latest_portfolio_metrics || null, latest_quote_outcomes: historyWriterState.latest_quote_outcomes || null, offsets: historyWriterState.offsets || {}, metrics_error: historyWriterState.metrics_error || null, quote_outcomes_error: historyWriterState.quote_outcomes_error || null, }, controls: listDashboardControls({ page: 'system' }), }; } function summarizeServiceSnapshot(snapshot, { authoritativeHealth = null, activeAlerts = [], nearIntentsStatus = null } = {}) { const state = snapshot.state || {}; const health = snapshot.health || {}; void authoritativeHealth; void activeAlerts; const freshnessAt = inferServiceFreshnessTimestamp(snapshot.service, state, health); const reachable = snapshot.reachable !== false; const online = reachable && health.ok !== false; const upstreamStatus = resolveServiceUpstreamStatus(snapshot.service, nearIntentsStatus); const upstreamDisrupted = upstreamStatus?.status === 'disrupted'; const healthStatus = upstreamDisrupted ? 'upstream_paused' : online ? 'online' : reachable ? 'reachable' : 'offline'; const healthLabel = upstreamDisrupted ? 'upstream paused' : healthStatus; const healthReasons = upstreamDisrupted && upstreamStatus.decisive_reason ? [upstreamStatus.decisive_reason] : []; return { service: snapshot.service, label: snapshot.label, base_url: snapshot.base_url, reachable, health_ok: healthStatus === 'online', health_status: healthStatus, health_label: healthLabel, health_reasons: healthReasons, upstream_status: upstreamStatus, highest_alert_severity: null, paused: state.paused ?? health.paused ?? null, armed: state.armed ?? null, draining: state.draining ?? null, freshness_at: freshnessAt, freshness_age_ms: ageMs(freshnessAt), last_error: state.last_error || health.last_error || null, summary: buildServiceSummary(snapshot.service, state), }; } const NEAR_INTENTS_RELAY_SERVICES = new Set(['near-intents-ingest', 'trade-executor']); function resolveServiceUpstreamStatus(service, nearIntentsStatus) { if (!NEAR_INTENTS_RELAY_SERVICES.has(service) || !nearIntentsStatus) return null; return { source: nearIntentsStatus.source || 'near_intents_status_page', status: nearIntentsStatus.status || 'unknown', label: nearIntentsStatus.label || nearIntentsStatus.status || 'unknown', observed_at: nearIntentsStatus.observed_at || null, decisive_reason: nearIntentsStatus.decisive_reason || null, current_incident_count: nearIntentsStatus.current_incident_count || 0, affected_services: nearIntentsStatus.affected_services || [], observed_incident_count: nearIntentsStatus.observed_incident_count ?? null, observed_affected_services: nearIntentsStatus.observed_affected_services || [], unrelated_incident_count: nearIntentsStatus.unrelated_incident_count || 0, quoting_stopped: nearIntentsStatus.quoting_stopped ?? null, }; } function buildServiceSummary(service, state) { switch (service) { case 'near-intents-ingest': return { connected: state.ingest?.connected ?? null, reconnect_count: state.ingest?.reconnect_count ?? null, active_pair: state.trading_config?.active_pair || null, enabled_pair_count: state.trading_config?.enabled_pair_count ?? 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, last_quote_outcomes_at: state.last_quote_outcomes_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, submitted_count: state.submitted_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, decision_reason: normalizeDecisionReason(trade.decision_reason), 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 enrichLifecycleRowForUi({ config, row }) { return { ...row, request_terms: buildLifecycleTerms({ config, terms: row.quote || row, }), submitted_terms: buildLifecycleTerms({ config, terms: row.command || row.execution || null, }), gross_edge_value_eure: estimateGrossEdgeValueEure(row), settlement_summary: buildSettlementSummary({ config, delta: row.attributed_inventory_delta, attributionStatus: row.attribution_status, attributionMethod: row.attribution_method, }), }; } function buildLifecycleTerms({ config, terms }) { if (!terms?.asset_in && !terms?.asset_out) return null; const assetIn = config.assetRegistry.get(terms.asset_in); const assetOut = config.assetRegistry.get(terms.asset_out); const amountIn = terms.amount_in ?? null; const amountOut = terms.amount_out ?? null; return { asset_in: terms.asset_in || null, asset_in_symbol: assetIn?.symbol || terms.asset_in || null, amount_in_units: amountIn, amount_in: amountIn == null ? null : formatUnits(amountIn, assetIn?.decimals || 0), asset_out: terms.asset_out || null, asset_out_symbol: assetOut?.symbol || terms.asset_out || null, amount_out_units: amountOut, amount_out: amountOut == null ? null : formatUnits(amountOut, assetOut?.decimals || 0), }; } function estimateGrossEdgeValueEure(row) { const edge = Number(row?.gross_edge_pct); const notional = Number(row?.eure_notional); if (!Number.isFinite(edge) || !Number.isFinite(notional)) return null; const value = (notional * edge) / 100; return value.toFixed(8).replace(/\.?0+$/, ''); } function buildSettlementSummary({ config, delta, attributionStatus, attributionMethod, subject = 'quote', }) { if (!delta?.delta_units) { return { status: attributionStatus || 'unattributed', method: attributionMethod || null, lines: [], text: attributionStatus === 'ambiguous' ? `Inventory movement is ambiguous and is not assigned to this ${subject}.` : `No settled inventory delta is linked to this ${subject}.`, }; } const lines = Object.entries(delta.delta_units).map(([assetId, units]) => { const asset = config.assetRegistry.get(assetId); const symbol = asset?.symbol || assetId; const formatted = formatUnits(units, asset?.decimals || 0); const signed = BigInt(String(units || '0')) > 0n ? `+${formatted}` : formatted; return { asset_id: assetId, symbol, units, amount: signed, }; }); return { status: attributionStatus || 'unattributed', method: attributionMethod || null, observed_at: delta.observed_at || null, previous_observed_at: delta.previous_observed_at || null, lines, text: lines.map((line) => `${line.amount} ${line.symbol}`).join(', '), caveat: delta.uncertainty || null, }; } 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: null, }); const key = buildFundingActivityKey(fallbackItem); const existing = itemsByKey.get(key); if (!existing || shouldReplaceFundingActivityItem(existing, fallbackItem)) { 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 shouldReplaceFundingActivityItem(existing, candidate) { if (!candidate) return false; if (!existing) return true; if (candidate.bridge_created_at && !existing.bridge_created_at) return true; const existingTs = timestampValue(fundingActivityTimestamp(existing)); const candidateTs = timestampValue(fundingActivityTimestamp(candidate)); return Number.isFinite(candidateTs) && (!Number.isFinite(existingTs) || candidateTs < existingTs); } 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, asset_symbol: asset?.label || 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_display: formatUnits(observation.amount || '0', asset?.decimals || 0), 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, created_at: details.created_at || payload.created_at || 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 bridgeCreatedAt = bridgeDepositObservedAt(deposit); const timestamp = bridgeCreatedAt || observedAt || null; return { funding_observation_id: null, asset_id: deposit?.asset_id || null, symbol: asset?.symbol || deposit?.asset_id || null, asset_symbol: asset?.label || 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_display: formatUnits(deposit?.amount || '0', asset?.decimals || 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, bridge_created_at: bridgeCreatedAt, }; } 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, pair_id: decision.pair_id || null, pair_config_id: decision.pair_config_id || null, pair_config_version: decision.pair_config_version || null, edge_bps: decision.edge_bps || null, direction: decision.direction || null, request_kind: decision.request_kind || null, decision: normalizeDecisionVerdict(decision.decision), decision_reason: normalizeDecisionReason(decision.decision_reason), 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 normalizeDecisionVerdict(value) { if (value === 'actionable') return 'approved'; return value || null; } function normalizeDecisionReason(value) { if (value === 'actionable') return 'strategy_approved'; return value || 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 || {}, transition_count: Number(alert.transition_count || 1), raised_count: Number(alert.raised_count || (alert.status === 'raised' ? 1 : 0)), cleared_count: Number(alert.cleared_count || (alert.status === 'cleared' ? 1 : 0)), }; } function summarizeRecentAlertTransitions(alerts) { const summaries = new Map(); for (const alert of alerts || []) { const key = buildAlertKey(alert); const existing = summaries.get(key); if (!existing) { summaries.set(key, { ...alert, transition_count: alert.transition_count || 1, raised_count: alert.status === 'raised' ? 1 : 0, cleared_count: alert.status === 'cleared' ? 1 : 0, }); continue; } existing.transition_count += 1; existing.raised_count += alert.status === 'raised' ? 1 : 0; existing.cleared_count += alert.status === 'cleared' ? 1 : 0; } return [...summaries.values()].sort((left, right) => sortTimestamps( right.cleared_at || right.raised_at || right.last_evaluated_at, left.cleared_at || left.raised_at || left.last_evaluated_at, )); } function normalizeDashboardLiveTopic(state, topic) { const config = state?.config || {}; const aliases = new Map([ [config.kafkaTopicNormSwapDemand, 'norm.swap_demand'], [config.kafkaTopicDecisionTradeDecision, 'decision.trade_decision'], [config.kafkaTopicCmdExecuteTrade, 'cmd.execute_trade'], [config.kafkaTopicRefMarketPrice, 'ref.market_price'], [config.kafkaTopicStateIntentInventory, 'state.intent_inventory'], [config.kafkaTopicOpsAlert, 'ops.alert'], [config.kafkaTopicOpsEnvironmentStatus, 'ops.environment_status'], [config.kafkaTopicExecTradeResult, 'exec.trade_result'], ]); return aliases.get(topic) || topic; } function buildQuoteLifecycleUpdate(state, { flashQuoteId = null } = {}) { const receivedAt = new Date().toISOString(); return { type: 'quote_lifecycle.updated', recent_lifecycle_rows: buildLiveQuoteLifecycleRows(state, { flashQuoteId, flashAt: receivedAt, }), flash_quote_id: flashQuoteId || null, received_at: receivedAt, }; } function appendUniqueRecentEvent(items, nextItem, limit, keyFn) { const nextKey = keyFn(nextItem); const deduped = [ nextItem, ...(items || []).filter((item) => keyFn(item) !== nextKey), ]; return deduped.slice(0, limit); } function livePayloadKey(entry, fields) { const payload = entry?.payload || entry || {}; for (const field of fields) { if (payload[field] != null && payload[field] !== '') return `${field}:${payload[field]}`; } return `event:${entry?.observed_at || entry?.ingested_at || JSON.stringify(payload)}`; } function normalizeLiveDecision(payload, event) { if (!payload?.decision_id && !payload?.quote_id) return null; const decisionAt = payload.decision_at || event.observed_at || event.ingested_at || null; return { observed_at: event.observed_at || decisionAt, ingested_at: event.ingested_at || null, payload: { ...payload, decision_at: decisionAt, }, }; } function normalizeLiveCommand(payload, event) { if (!payload?.command_id && !payload?.decision_id && !payload?.quote_id) return null; return { observed_at: event.observed_at || event.ingested_at || null, ingested_at: event.ingested_at || null, payload: { ...payload, amount_in: payload.quote_output?.amount_in ?? payload.proposed_amount_in ?? payload.amount_in ?? null, amount_out: payload.quote_output?.amount_out ?? payload.proposed_amount_out ?? payload.amount_out ?? null, }, }; } function normalizeLiveExecutionResult(payload, event) { if (!payload?.command_id && !payload?.decision_id && !payload?.quote_id) return null; return { command_id: payload.command_id || null, decision_id: payload.decision_id || null, execution_key: payload.execution_key || null, quote_id: payload.quote_id || null, pair: payload.pair || null, result_at: event.observed_at || event.ingested_at || new Date().toISOString(), status: payload.status || null, result_code: payload.result_code || null, outcome_status: payload.outcome_status || payload.venue_outcome_status || payload.trade_outcome_status || null, outcome_reason: payload.outcome_reason || payload.venue_outcome_reason || payload.trade_outcome_reason || null, attribution_status: payload.attribution_status || null, attribution_method: payload.attribution_method || null, attributed_inventory_delta: payload.attributed_inventory_delta || null, venue_response: payload.venue_response || null, error_message: payload.error?.message || null, note: payload.note || null, }; } 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, btcAssets = null, eureAsset, }) { if (!inventory || !marketPrice || !btcAsset || !eureAsset) return null; const effectiveBtcAssets = btcAssets?.length ? btcAssets : [btcAsset]; const btcScaled = effectiveBtcAssets.reduce((total, asset) => { const units = String(inventory.spendable?.[asset.assetId] || '0'); return total + unitsToScaledDecimal(units, asset.decimals); }, 0n); const eureUnits = String(inventory.spendable?.[eureAsset.assetId] || '0'); 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; }