unrip/src/core/operator-dashboard.mjs
philipp 8f109a7463
Some checks failed
deploy / deploy (push) Failing after 40s
Value tracked USDC in portfolio metrics
Proof: Dashboard portfolio metrics now include DB-tracked USDC balances valued from live BTC/EUR and BTC/USDC reference prices, with regression coverage for the observed USDC inventory case.

Assumptions: USDC is cash-equivalent for valuation when a fresh BTC/USDC reference event is available; live trading safety remains governed by pair config and price route checks.

Still fake: Portfolio valuation still does not provide fee-complete realized PnL or generalized valuation for every imported non-stable asset.
2026-05-18 17:51:31 +02:00

2455 lines
88 KiB
JavaScript

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;
}