unrip/src/lib/postgres.mjs
philipp 88d635033c
Some checks failed
deploy / deploy (push) Failing after 35s
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:48:18 +02:00

3704 lines
116 KiB
JavaScript

import { Pool } from 'pg';
import { deriveIntentRequestOutcomeRecords } from '../core/intent-request-outcomes.mjs';
import { buildCashEquivalentValuationAssets } from '../core/portfolio-metrics.mjs';
import { deriveQuoteOutcomeRecords } from '../core/quote-outcomes.mjs';
import {
CURRENT_NBTC_ASSET_ID,
CURRENT_USDC_ASSET_ID,
ONE_CLICK_TOKENS_URL,
buildBtcUsdcPriceRoute,
buildSeedAssets,
buildSeedPairs,
buildSeedPriceRoute,
buildSeedStrategyConfig,
hashJson,
normalizeOneClickTokenResponse,
normalizePairMode,
pairCanMake,
pairCanObserve,
pairCanTake,
} from '../core/trading-config.mjs';
const TABLES = [
'raw_near_intents_quotes',
'swap_demand_events',
'market_price_events',
'intent_inventory_snapshots',
'liquidity_actions',
'funding_observations',
'ops_alerts',
'environment_status_events',
'trade_decisions',
'execute_trade_commands',
'trade_execution_results',
'intent_request_preflights',
'intent_request_submission_results',
];
const PORTFOLIO_METRICS_TABLE = 'portfolio_metrics_snapshots';
const QUOTE_OUTCOMES_TABLE = 'quote_outcome_attributions';
const INTENT_REQUEST_OUTCOMES_TABLE = 'intent_request_outcomes';
const SUPPORTED_ASSET_IMPORT_RUNS_TABLE = 'supported_asset_import_runs';
const TRADING_ASSETS_TABLE = 'trading_assets';
const TRADING_PAIRS_TABLE = 'trading_pairs';
const PAIR_STRATEGY_CONFIGS_TABLE = 'pair_strategy_configs';
const PAIR_PRICE_ROUTES_TABLE = 'pair_price_routes';
const PAIR_CONFIG_AUDIT_LOG_TABLE = 'pair_config_audit_log';
const CREDITED_LIQUIDITY_STATUSES = ['CREDITED', 'COMPLETED', 'FINALIZED', 'SETTLED'];
const COMPLETED_WITHDRAWAL_STATUSES = ['COMPLETED', 'FINALIZED', 'SETTLED'];
const REFRESHABLE_INTENT_REQUEST_OUTCOME_STATUSES = [
'draft',
'submitted',
'accepted_by_relay',
'awaiting_settlement',
];
export function createPostgresPool({ connectionString }) {
return new Pool({
connectionString,
});
}
async function withTransaction(pool, operation) {
if (typeof pool.connect !== 'function') return operation(pool);
const client = await pool.connect();
try {
await client.query('BEGIN');
const result = await operation(client);
await client.query('COMMIT');
return result;
} catch (error) {
try {
await client.query('ROLLBACK');
} catch {
// Preserve the original transaction failure.
}
throw error;
} finally {
client.release();
}
}
export async function ensureHistorySchema(pool) {
await ensureTradingConfigSchema(pool);
for (const table of TABLES) {
await pool.query(`
CREATE TABLE IF NOT EXISTS ${table} (
event_id TEXT PRIMARY KEY,
topic TEXT NOT NULL,
venue TEXT NOT NULL,
source TEXT,
event_type TEXT NOT NULL,
observed_at TIMESTAMPTZ,
ingested_at TIMESTAMPTZ NOT NULL,
quote_id TEXT,
pair TEXT,
decision_key TEXT,
payload JSONB NOT NULL,
raw JSONB
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${table}_quote_id_idx
ON ${table} (quote_id)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${table}_decision_key_idx
ON ${table} (decision_key)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${table}_ingested_at_idx
ON ${table} (ingested_at DESC)
`);
}
await ensureExpressionIndex(pool, {
name: 'funding_observations_tx_hash_idx',
table: 'funding_observations',
expression: "(payload->>'tx_hash')",
});
await ensureExpressionIndex(pool, {
name: 'funding_observations_handle_idx',
table: 'funding_observations',
expression: "(payload->>'funding_handle')",
});
await ensureExpressionIndex(pool, {
name: 'funding_observations_asset_id_idx',
table: 'funding_observations',
expression: "(payload->>'asset_id')",
});
await ensureExpressionIndex(pool, {
name: 'funding_observations_chain_idx',
table: 'funding_observations',
expression: "(payload->>'chain')",
});
await ensureExpressionIndex(pool, {
name: 'funding_observations_status_idx',
table: 'funding_observations',
expression: "(payload->>'status')",
});
await ensureExpressionIndex(pool, {
name: 'ops_alerts_alert_code_idx',
table: 'ops_alerts',
expression: "(payload->>'alert_code')",
});
await ensureExpressionIndex(pool, {
name: 'ops_alerts_status_idx',
table: 'ops_alerts',
expression: "(payload->>'status')",
});
await ensureExpressionIndex(pool, {
name: 'ops_alerts_asset_id_idx',
table: 'ops_alerts',
expression: "(payload->>'asset_id')",
});
await ensureExpressionIndex(pool, {
name: 'environment_status_events_key_idx',
table: 'environment_status_events',
expression: "(payload->>'environment_key')",
});
await ensureExpressionIndex(pool, {
name: 'environment_status_events_status_idx',
table: 'environment_status_events',
expression: "(payload->>'status')",
});
await ensureExpressionIndex(pool, {
name: 'environment_status_events_fingerprint_idx',
table: 'environment_status_events',
expression: "(payload->>'status_fingerprint')",
});
await pool.query(`
CREATE TABLE IF NOT EXISTS ${PORTFOLIO_METRICS_TABLE} (
metric_id TEXT PRIMARY KEY,
computed_at TIMESTAMPTZ NOT NULL,
baseline_anchor_at TIMESTAMPTZ,
baseline_status TEXT NOT NULL,
payload JSONB NOT NULL
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${PORTFOLIO_METRICS_TABLE}_computed_at_idx
ON ${PORTFOLIO_METRICS_TABLE} (computed_at DESC)
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS notification_deliveries (
notification_key TEXT PRIMARY KEY,
notification_type TEXT NOT NULL,
source_kind TEXT NOT NULL,
source_id TEXT,
status TEXT NOT NULL,
attempt_count INTEGER NOT NULL DEFAULT 0,
first_attempt_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_attempt_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
delivered_at TIMESTAMPTZ,
payload JSONB NOT NULL,
response JSONB,
error JSONB
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS notification_deliveries_status_idx
ON notification_deliveries (status, last_attempt_at DESC)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS notification_deliveries_type_idx
ON notification_deliveries (notification_type, last_attempt_at DESC)
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS ${QUOTE_OUTCOMES_TABLE} (
quote_id TEXT PRIMARY KEY,
decision_id TEXT,
command_id TEXT,
execution_result_status TEXT NOT NULL,
execution_result_code TEXT,
submitted_at TIMESTAMPTZ,
command_at TIMESTAMPTZ,
outcome_status TEXT NOT NULL,
outcome_observed_at TIMESTAMPTZ,
outcome_source TEXT NOT NULL,
attribution_status TEXT NOT NULL,
attribution_method TEXT,
attributed_inventory_delta JSONB,
computed_at TIMESTAMPTZ NOT NULL,
payload JSONB NOT NULL
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${QUOTE_OUTCOMES_TABLE}_outcome_observed_at_idx
ON ${QUOTE_OUTCOMES_TABLE} (outcome_observed_at DESC)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${QUOTE_OUTCOMES_TABLE}_outcome_status_idx
ON ${QUOTE_OUTCOMES_TABLE} (outcome_status)
`);
await ensureExpressionIndex(pool, {
name: 'intent_request_preflights_request_id_idx',
table: 'intent_request_preflights',
expression: "(payload->>'request_id')",
});
await ensureExpressionIndex(pool, {
name: 'intent_request_preflights_idempotency_key_idx',
table: 'intent_request_preflights',
expression: "(payload->>'idempotency_key')",
});
await ensureExpressionIndex(pool, {
name: 'intent_request_submission_results_request_id_idx',
table: 'intent_request_submission_results',
expression: "(payload->>'request_id')",
});
await ensureExpressionIndex(pool, {
name: 'intent_request_submission_results_idempotency_key_idx',
table: 'intent_request_submission_results',
expression: "(payload->>'idempotency_key')",
});
await pool.query(`
CREATE TABLE IF NOT EXISTS ${INTENT_REQUEST_OUTCOMES_TABLE} (
request_id TEXT PRIMARY KEY,
idempotency_key TEXT NOT NULL,
submission_id TEXT,
intent_hash TEXT,
submission_status TEXT,
relay_status TEXT,
submitted_at TIMESTAMPTZ,
outcome_status TEXT NOT NULL,
outcome_observed_at TIMESTAMPTZ,
outcome_source TEXT NOT NULL,
outcome_reason TEXT NOT NULL,
attribution_status TEXT NOT NULL,
attribution_method TEXT,
attributed_inventory_delta JSONB,
computed_at TIMESTAMPTZ NOT NULL,
payload JSONB NOT NULL
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${INTENT_REQUEST_OUTCOMES_TABLE}_outcome_observed_at_idx
ON ${INTENT_REQUEST_OUTCOMES_TABLE} (outcome_observed_at DESC)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${INTENT_REQUEST_OUTCOMES_TABLE}_outcome_status_idx
ON ${INTENT_REQUEST_OUTCOMES_TABLE} (outcome_status)
`);
}
export async function ensureTradingConfigSchema(pool) {
await pool.query(`
CREATE TABLE IF NOT EXISTS ${SUPPORTED_ASSET_IMPORT_RUNS_TABLE} (
run_id TEXT PRIMARY KEY,
source_url TEXT NOT NULL,
fetched_at TIMESTAMPTZ NOT NULL,
status TEXT NOT NULL,
token_count INTEGER NOT NULL DEFAULT 0,
added_count INTEGER NOT NULL DEFAULT 0,
updated_count INTEGER NOT NULL DEFAULT 0,
unchanged_count INTEGER NOT NULL DEFAULT 0,
retired_count INTEGER NOT NULL DEFAULT 0,
raw_response_hash TEXT,
error TEXT,
raw_response JSONB
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${SUPPORTED_ASSET_IMPORT_RUNS_TABLE}_fetched_at_idx
ON ${SUPPORTED_ASSET_IMPORT_RUNS_TABLE} (fetched_at DESC)
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS ${TRADING_ASSETS_TABLE} (
asset_id TEXT PRIMARY KEY,
venue TEXT NOT NULL,
symbol TEXT NOT NULL,
label TEXT NOT NULL,
decimals INTEGER NOT NULL,
blockchain TEXT,
chain TEXT,
contract_address TEXT,
latest_price TEXT,
price_updated_at TIMESTAMPTZ,
supported BOOLEAN NOT NULL DEFAULT false,
retired_at TIMESTAMPTZ,
enabled_for_inventory BOOLEAN NOT NULL DEFAULT false,
role TEXT,
withdraw_address TEXT,
raw_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
first_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_supported_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${TRADING_ASSETS_TABLE}_supported_idx
ON ${TRADING_ASSETS_TABLE} (supported, updated_at DESC)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${TRADING_ASSETS_TABLE}_inventory_idx
ON ${TRADING_ASSETS_TABLE} (enabled_for_inventory, asset_id)
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS ${TRADING_PAIRS_TABLE} (
pair_id TEXT PRIMARY KEY,
venue TEXT NOT NULL,
asset_in TEXT NOT NULL REFERENCES ${TRADING_ASSETS_TABLE}(asset_id),
asset_out TEXT NOT NULL REFERENCES ${TRADING_ASSETS_TABLE}(asset_id),
mode TEXT NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT false,
status TEXT NOT NULL DEFAULT 'disabled',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (venue, asset_in, asset_out)
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${TRADING_PAIRS_TABLE}_enabled_idx
ON ${TRADING_PAIRS_TABLE} (enabled, status, updated_at DESC)
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS ${PAIR_STRATEGY_CONFIGS_TABLE} (
config_id TEXT PRIMARY KEY,
pair_id TEXT NOT NULL REFERENCES ${TRADING_PAIRS_TABLE}(pair_id),
version INTEGER NOT NULL,
active BOOLEAN NOT NULL DEFAULT false,
edge_bps INTEGER NOT NULL,
max_notional NUMERIC NOT NULL,
min_notional NUMERIC NOT NULL DEFAULT 0,
slippage_bps INTEGER NOT NULL DEFAULT 0,
min_deadline_ms INTEGER NOT NULL,
price_max_age_ms INTEGER NOT NULL,
inventory_max_age_ms INTEGER NOT NULL,
request_default_notional NUMERIC,
request_max_notional NUMERIC,
request_max_slippage_bps INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT NOT NULL,
reason TEXT,
UNIQUE (pair_id, version)
)
`);
await pool.query(`
CREATE UNIQUE INDEX IF NOT EXISTS ${PAIR_STRATEGY_CONFIGS_TABLE}_active_one_idx
ON ${PAIR_STRATEGY_CONFIGS_TABLE} (pair_id)
WHERE active
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS ${PAIR_PRICE_ROUTES_TABLE} (
route_id TEXT PRIMARY KEY,
pair_id TEXT NOT NULL REFERENCES ${TRADING_PAIRS_TABLE}(pair_id),
source TEXT NOT NULL,
base_asset_id TEXT NOT NULL REFERENCES ${TRADING_ASSETS_TABLE}(asset_id),
quote_asset_id TEXT NOT NULL REFERENCES ${TRADING_ASSETS_TABLE}(asset_id),
route_config JSONB NOT NULL DEFAULT '{}'::jsonb,
max_age_ms INTEGER NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${PAIR_PRICE_ROUTES_TABLE}_pair_enabled_idx
ON ${PAIR_PRICE_ROUTES_TABLE} (pair_id, enabled)
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS ${PAIR_CONFIG_AUDIT_LOG_TABLE} (
audit_id TEXT PRIMARY KEY,
entity_type TEXT NOT NULL,
entity_id TEXT NOT NULL,
action TEXT NOT NULL,
old_value JSONB,
new_value JSONB,
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
changed_by TEXT NOT NULL,
reason TEXT
)
`);
await pool.query(`
CREATE INDEX IF NOT EXISTS ${PAIR_CONFIG_AUDIT_LOG_TABLE}_entity_idx
ON ${PAIR_CONFIG_AUDIT_LOG_TABLE} (entity_type, entity_id, changed_at DESC)
`);
}
export async function seedTradingConfig(pool, {
now = new Date().toISOString(),
changedBy = 'repo_seed',
} = {}) {
await ensureTradingConfigSchema(pool);
for (const asset of buildSeedAssets()) {
await upsertSeedAsset(pool, { asset, now });
}
for (const pair of buildSeedPairs()) {
await upsertSeedPair(pool, { pair, now, preserveRuntimeState: true });
await upsertSeedStrategyConfig(pool, {
config: buildSeedStrategyConfig(pair.pairId, { createdBy: changedBy }),
});
await upsertSeedPriceRoute(pool, {
route: buildSeedPriceRoute(pair.pairId),
now,
});
}
await seedKnownEnabledPairRuntimeConfig(pool, { now });
return loadTradingConfig(pool);
}
export async function importSupportedAssets(pool, {
sourceUrl = ONE_CLICK_TOKENS_URL,
fetchedAt = new Date().toISOString(),
fetchImpl = globalThis.fetch,
response = null,
} = {}) {
await ensureTradingConfigSchema(pool);
let rawResponse = response;
let rawResponseHash = null;
let runId = null;
try {
if (rawResponse == null) {
if (typeof fetchImpl !== 'function') throw new Error('fetch implementation is unavailable');
const fetchResponse = await fetchImpl(sourceUrl);
const text = await fetchResponse.text();
if (!fetchResponse.ok) throw new Error(`HTTP ${fetchResponse.status}: ${text.slice(0, 200)}`);
rawResponse = text ? JSON.parse(text) : null;
}
const normalizedTokens = normalizeOneClickTokenResponse(rawResponse);
rawResponseHash = hashJson(rawResponse);
runId = `asset-import:${Date.parse(fetchedAt)}:${rawResponseHash.slice(0, 16)}`;
const existing = await loadTradingAssetsById(pool);
let addedCount = 0;
let updatedCount = 0;
let unchangedCount = 0;
for (const token of normalizedTokens) {
const previous = existing.get(token.assetId) || null;
if (!previous) addedCount += 1;
else if (importedAssetChanged(previous, token)) updatedCount += 1;
else unchangedCount += 1;
await upsertImportedAsset(pool, {
asset: token,
fetchedAt,
});
}
const importedAssetIds = normalizedTokens.map((token) => token.assetId);
const retiredResult = await pool.query(
`
UPDATE ${TRADING_ASSETS_TABLE}
SET
supported = false,
retired_at = COALESCE(retired_at, $1),
updated_at = $1
WHERE venue = 'near-intents'
AND supported = true
AND NOT (asset_id = ANY($2::text[]))
RETURNING asset_id
`,
[fetchedAt, importedAssetIds],
);
const summary = {
run_id: runId,
source_url: sourceUrl,
fetched_at: fetchedAt,
status: 'success',
token_count: normalizedTokens.length,
added_count: addedCount,
updated_count: updatedCount,
unchanged_count: unchangedCount,
retired_count: retiredResult.rowCount,
raw_response_hash: rawResponseHash,
error: null,
raw_response: rawResponse,
};
await insertAssetImportRun(pool, summary);
return publicAssetImportRunSummary(summary);
} catch (error) {
const fallbackHash = rawResponse == null ? null : hashJson(rawResponse);
runId ||= `asset-import:${Date.parse(fetchedAt)}:${fallbackHash?.slice(0, 16) || 'failed'}`;
const summary = {
run_id: runId,
source_url: sourceUrl,
fetched_at: fetchedAt,
status: 'failed',
token_count: 0,
added_count: 0,
updated_count: 0,
unchanged_count: 0,
retired_count: 0,
raw_response_hash: fallbackHash,
error: error.message,
raw_response: rawResponse,
};
await insertAssetImportRun(pool, summary);
throw Object.assign(error, { importRun: publicAssetImportRunSummary(summary) });
}
}
export async function loadTradingConfig(pool) {
await ensureTradingConfigSchema(pool);
const [
assetResult,
pairResult,
strategyResult,
routeResult,
latestImportResult,
] = await Promise.all([
pool.query(`
SELECT *
FROM ${TRADING_ASSETS_TABLE}
ORDER BY symbol ASC, asset_id ASC
`),
pool.query(`
SELECT *
FROM ${TRADING_PAIRS_TABLE}
ORDER BY created_at ASC, pair_id ASC
`),
pool.query(`
SELECT *
FROM ${PAIR_STRATEGY_CONFIGS_TABLE}
WHERE active = true
ORDER BY pair_id ASC, version DESC
`),
pool.query(`
SELECT *
FROM ${PAIR_PRICE_ROUTES_TABLE}
WHERE enabled = true
ORDER BY pair_id ASC, created_at DESC
`),
pool.query(`
SELECT *
FROM ${SUPPORTED_ASSET_IMPORT_RUNS_TABLE}
ORDER BY fetched_at DESC
LIMIT 1
`),
]);
return buildTradingConfigSnapshot({
assetRows: assetResult.rows,
pairRows: pairResult.rows,
strategyRows: strategyResult.rows,
routeRows: routeResult.rows,
latestImportRun: latestImportResult.rows[0] || null,
});
}
export function createTradingConfigStore({
pool,
cacheTtlMs = 5_000,
logger = null,
} = {}) {
if (!pool) throw new Error('pool is required');
let cached = null;
let cachedAtMs = 0;
let lastError = null;
async function refresh({ force = false } = {}) {
const nowMs = Date.now();
if (!force && cached && nowMs - cachedAtMs <= cacheTtlMs) return cached;
try {
cached = await loadTradingConfig(pool);
cachedAtMs = nowMs;
lastError = null;
return cached;
} catch (error) {
lastError = error;
logger?.error?.('trading_config_load_failed', {
details: { error: error.message },
});
cached = buildFailClosedTradingConfig(error);
cachedAtMs = nowMs;
return cached;
}
}
return {
getConfig: refresh,
async forceRefresh() {
return refresh({ force: true });
},
getCachedConfig() {
return cached || buildFailClosedTradingConfig(lastError || new Error('config not loaded'));
},
getState() {
return summarizeTradingConfigSnapshot(
cached || buildFailClosedTradingConfig(lastError || new Error('config not loaded')),
);
},
};
}
export async function loadAssetCatalogSummary(pool, { limit = 250 } = {}) {
await ensureTradingConfigSchema(pool);
const boundedLimit = Math.max(1, Number(limit) || 50);
const [latestImportResult, countResult, assetResult] = await Promise.all([
pool.query(`
SELECT *
FROM ${SUPPORTED_ASSET_IMPORT_RUNS_TABLE}
ORDER BY fetched_at DESC
LIMIT 1
`),
pool.query(`
SELECT
COUNT(*)::INT AS known_count,
COUNT(*) FILTER (WHERE supported)::INT AS supported_count,
COUNT(*) FILTER (WHERE retired_at IS NOT NULL OR supported = false)::INT AS retired_count,
COUNT(*) FILTER (WHERE enabled_for_inventory)::INT AS inventory_enabled_count
FROM ${TRADING_ASSETS_TABLE}
`),
pool.query(`
SELECT
asset_id,
venue,
symbol,
label,
decimals,
blockchain,
chain,
contract_address,
latest_price,
price_updated_at,
supported,
retired_at,
enabled_for_inventory,
role,
withdraw_address,
raw_payload <> '{}'::jsonb AS raw_payload_available,
updated_at
FROM ${TRADING_ASSETS_TABLE}
ORDER BY symbol ASC, asset_id ASC
LIMIT $1
`, [boundedLimit]),
]);
const counts = countResult.rows[0] || {};
return {
latest_import: normalizeAssetImportRunRow(latestImportResult.rows[0] || null),
counts: {
known: Number(counts.known_count || 0),
supported: Number(counts.supported_count || 0),
retired: Number(counts.retired_count || 0),
inventory_enabled: Number(counts.inventory_enabled_count || 0),
},
items: assetResult.rows.map(normalizeAssetCatalogSummaryRow),
};
}
export async function loadPairConfigSummary(pool) {
const snapshot = await loadTradingConfig(pool);
return {
ok: snapshot.ok,
block_reason: snapshot.blockReason,
loaded_at: snapshot.loadedAt,
pairs: snapshot.pairs,
};
}
export async function createPairStrategyConfigVersion(pool, {
pairId = null,
pair = null,
edgeBps = null,
maxNotional = null,
minNotional = null,
slippageBps = null,
minDeadlineMs = null,
priceMaxAgeMs = null,
inventoryMaxAgeMs = null,
requestDefaultNotional = undefined,
requestMaxNotional = undefined,
requestMaxSlippageBps = undefined,
changedBy = 'operator',
reason = 'operator config update',
} = {}) {
await ensureTradingConfigSchema(pool);
const resolvedPairId = pairId || pair;
if (!resolvedPairId) throw new Error('pair_id is required');
return withTransaction(pool, async (client) => {
const activeResult = await client.query(
`
SELECT *
FROM ${PAIR_STRATEGY_CONFIGS_TABLE}
WHERE pair_id = $1 AND active = true
ORDER BY version DESC
LIMIT 1
`,
[resolvedPairId],
);
const active = activeResult.rows[0];
if (!active) throw new Error(`active strategy config missing for pair ${resolvedPairId}`);
const nextVersion = Number(active.version || 0) + 1;
const nextEdgeBps = edgeBps == null ? Number(active.edge_bps) : Number(edgeBps);
if (!Number.isInteger(nextEdgeBps) || nextEdgeBps <= 0) {
throw new Error('edge_bps must be a positive integer');
}
const nextMaxNotional = positiveNumberStringOrDefault(maxNotional, active.max_notional, 'max_notional');
const nextConfig = {
configId: `${resolvedPairId}:v${nextVersion}`,
pairId: resolvedPairId,
version: nextVersion,
edgeBps: nextEdgeBps,
maxNotional: nextMaxNotional,
minNotional: minNotional == null ? String(active.min_notional) : String(minNotional),
slippageBps: slippageBps == null ? Number(active.slippage_bps) : Number(slippageBps),
minDeadlineMs: minDeadlineMs == null ? Number(active.min_deadline_ms) : Number(minDeadlineMs),
priceMaxAgeMs: priceMaxAgeMs == null ? Number(active.price_max_age_ms) : Number(priceMaxAgeMs),
inventoryMaxAgeMs:
inventoryMaxAgeMs == null ? Number(active.inventory_max_age_ms) : Number(inventoryMaxAgeMs),
requestDefaultNotional:
requestDefaultNotional === undefined
? active.request_default_notional == null ? null : String(active.request_default_notional)
: nullablePositiveNumberString(requestDefaultNotional, 'request_default_notional'),
requestMaxNotional:
requestMaxNotional === undefined
? active.request_max_notional == null ? null : String(active.request_max_notional)
: nullablePositiveNumberString(requestMaxNotional, 'request_max_notional'),
requestMaxSlippageBps:
requestMaxSlippageBps === undefined
? active.request_max_slippage_bps == null ? null : Number(active.request_max_slippage_bps)
: nullableNonNegativeInteger(requestMaxSlippageBps, 'request_max_slippage_bps'),
createdBy: changedBy,
reason,
};
await client.query(
`UPDATE ${PAIR_STRATEGY_CONFIGS_TABLE} SET active = false WHERE pair_id = $1 AND active = true`,
[resolvedPairId],
);
await insertPairStrategyConfig(client, { config: nextConfig, active: true });
await insertConfigAuditLog(client, {
entityType: 'pair_strategy_config',
entityId: resolvedPairId,
action: 'version_created',
oldValue: normalizeStrategyConfigRow(active),
newValue: nextConfig,
changedBy,
reason,
});
return normalizeStrategyConfigRow({
...active,
config_id: nextConfig.configId,
pair_id: nextConfig.pairId,
version: nextConfig.version,
active: true,
edge_bps: nextConfig.edgeBps,
max_notional: nextConfig.maxNotional,
min_notional: nextConfig.minNotional,
slippage_bps: nextConfig.slippageBps,
min_deadline_ms: nextConfig.minDeadlineMs,
price_max_age_ms: nextConfig.priceMaxAgeMs,
inventory_max_age_ms: nextConfig.inventoryMaxAgeMs,
request_default_notional: nextConfig.requestDefaultNotional,
request_max_notional: nextConfig.requestMaxNotional,
request_max_slippage_bps: nextConfig.requestMaxSlippageBps,
created_by: changedBy,
reason,
});
});
}
export async function enableObserveOnlyPair(pool, {
venue = 'near-intents',
assetIn,
assetOut,
changedBy = 'operator',
reason = 'operator enabled observe-only pair',
} = {}) {
await ensureTradingConfigSchema(pool);
if (!assetIn || !assetOut) throw new Error('asset_in and asset_out are required');
const pairId = `${assetIn}->${assetOut}`;
const existingResult = await pool.query(
`
SELECT *
FROM ${TRADING_PAIRS_TABLE}
WHERE pair_id = $1
LIMIT 1
`,
[pairId],
);
const existingPair = existingResult.rows[0] ? normalizeTradingPairRow(existingResult.rows[0]) : null;
if (existingPair?.enabled && existingPair.status !== 'disabled') {
return existingPair;
}
const pair = {
pairId,
venue,
assetIn,
assetOut,
mode: 'observe_only',
enabled: true,
status: 'observe_only',
};
await upsertSeedPair(pool, { pair, now: new Date().toISOString() });
await insertConfigAuditLog(pool, {
entityType: 'trading_pair',
entityId: pairId,
action: 'observe_only_enabled',
oldValue: null,
newValue: pair,
changedBy,
reason,
});
return pair;
}
export async function setTradingPairMode(pool, {
venue = 'near-intents',
pairId = null,
pair = null,
assetIn = null,
assetOut = null,
mode = 'observe_only',
edgeBps = null,
maxNotional = null,
minNotional = null,
slippageBps = null,
minDeadlineMs = null,
priceMaxAgeMs = null,
inventoryMaxAgeMs = null,
requestDefaultNotional = undefined,
requestMaxNotional = undefined,
requestMaxSlippageBps = undefined,
changedBy = 'operator',
reason = 'operator pair mode update',
} = {}) {
await ensureTradingConfigSchema(pool);
const normalizedMode = normalizePairMode(mode);
const resolvedPairId = pairId || pair || (assetIn && assetOut ? `${assetIn}->${assetOut}` : null);
if (!resolvedPairId) throw new Error('pair_id or asset_in/asset_out is required');
return withTransaction(pool, async (client) => {
const existingResult = await client.query(
`
SELECT *
FROM ${TRADING_PAIRS_TABLE}
WHERE pair_id = $1
LIMIT 1
`,
[resolvedPairId],
);
const existingPair = existingResult.rows[0] ? normalizeTradingPairRow(existingResult.rows[0]) : null;
const [pairAssetIn, pairAssetOut] = splitPairId(resolvedPairId);
const resolvedAssetIn = assetIn || existingPair?.assetIn || pairAssetIn;
const resolvedAssetOut = assetOut || existingPair?.assetOut || pairAssetOut;
if (!resolvedAssetIn || !resolvedAssetOut) throw new Error('asset_in and asset_out are required');
const assets = await loadTradingAssetsById(client);
if (!assets.has(resolvedAssetIn)) throw new Error(`asset_in is not registered: ${resolvedAssetIn}`);
if (!assets.has(resolvedAssetOut)) throw new Error(`asset_out is not registered: ${resolvedAssetOut}`);
const nextPair = {
pairId: resolvedPairId,
venue: existingPair?.venue || venue,
assetIn: resolvedAssetIn,
assetOut: resolvedAssetOut,
mode: normalizedMode,
enabled: true,
status: normalizedMode,
};
await upsertSeedPair(client, { pair: nextPair, now: new Date().toISOString() });
let strategyConfig = null;
if (pairCanMake(nextPair) || pairCanTake(nextPair)) {
await enableInventoryForAssets(client, {
assetIds: [resolvedAssetIn, resolvedAssetOut],
now: new Date().toISOString(),
});
const activeConfigResult = await client.query(
`
SELECT *
FROM ${PAIR_STRATEGY_CONFIGS_TABLE}
WHERE pair_id = $1 AND active = true
ORDER BY version DESC
LIMIT 1
`,
[resolvedPairId],
);
strategyConfig = activeConfigResult.rows[0]
? normalizeStrategyConfigRow(activeConfigResult.rows[0])
: null;
if (!strategyConfig) {
const nextConfig = buildInitialPairStrategyConfig(resolvedPairId, {
edgeBps,
maxNotional,
minNotional,
slippageBps,
minDeadlineMs,
priceMaxAgeMs,
inventoryMaxAgeMs,
requestDefaultNotional,
requestMaxNotional,
requestMaxSlippageBps,
changedBy,
reason,
});
await insertPairStrategyConfig(client, { config: nextConfig, active: true });
strategyConfig = normalizeStrategyConfigRow({
config_id: nextConfig.configId,
pair_id: nextConfig.pairId,
version: nextConfig.version,
active: true,
edge_bps: nextConfig.edgeBps,
max_notional: nextConfig.maxNotional,
min_notional: nextConfig.minNotional,
slippage_bps: nextConfig.slippageBps,
min_deadline_ms: nextConfig.minDeadlineMs,
price_max_age_ms: nextConfig.priceMaxAgeMs,
inventory_max_age_ms: nextConfig.inventoryMaxAgeMs,
request_default_notional: nextConfig.requestDefaultNotional,
request_max_notional: nextConfig.requestMaxNotional,
request_max_slippage_bps: nextConfig.requestMaxSlippageBps,
created_by: changedBy,
reason,
});
await insertConfigAuditLog(client, {
entityType: 'pair_strategy_config',
entityId: resolvedPairId,
action: 'initial_version_created',
oldValue: null,
newValue: strategyConfig,
changedBy,
reason,
});
}
const knownRoute = buildKnownPriceRouteForPair(nextPair);
if (knownRoute) {
await upsertSeedPriceRoute(client, {
route: knownRoute,
now: new Date().toISOString(),
});
}
}
await insertConfigAuditLog(client, {
entityType: 'trading_pair',
entityId: resolvedPairId,
action: 'mode_set',
oldValue: existingPair,
newValue: nextPair,
changedBy,
reason,
});
return {
...nextPair,
strategyConfig,
};
});
}
export async function pauseTradingPair(pool, {
pairId = null,
pair = null,
changedBy = 'operator',
reason = 'operator paused pair',
} = {}) {
await ensureTradingConfigSchema(pool);
const resolvedPairId = pairId || pair;
if (!resolvedPairId) throw new Error('pair_id is required');
return withTransaction(pool, async (client) => {
const existingResult = await client.query(
`
SELECT *
FROM ${TRADING_PAIRS_TABLE}
WHERE pair_id = $1
LIMIT 1
`,
[resolvedPairId],
);
const existingPair = existingResult.rows[0] ? normalizeTradingPairRow(existingResult.rows[0]) : null;
if (!existingPair) throw new Error(`trading pair not found: ${resolvedPairId}`);
const nextPair = {
pairId: existingPair.pairId,
venue: existingPair.venue,
assetIn: existingPair.assetIn,
assetOut: existingPair.assetOut,
mode: existingPair.mode,
enabled: false,
status: 'disabled',
};
await upsertSeedPair(client, { pair: nextPair, now: new Date().toISOString() });
await insertConfigAuditLog(client, {
entityType: 'trading_pair',
entityId: resolvedPairId,
action: 'paused',
oldValue: existingPair,
newValue: nextPair,
changedBy,
reason,
});
return nextPair;
});
}
function buildTradingConfigSnapshot({
assetRows,
pairRows,
strategyRows,
routeRows,
latestImportRun,
}) {
const loadedAt = new Date().toISOString();
const assets = assetRows.map(normalizeTradingAssetRow);
const assetRegistry = new Map(assets.map((asset) => [asset.assetId, asset]));
const strategyByPairId = new Map(
strategyRows.map((row) => [row.pair_id, normalizeStrategyConfigRow(row)]),
);
const routeByPairId = new Map();
for (const row of routeRows) {
if (!routeByPairId.has(row.pair_id)) routeByPairId.set(row.pair_id, normalizePriceRouteRow(row));
}
const pairs = pairRows.map((row) => {
const pair = normalizeTradingPairRow(row);
const assetIn = assetRegistry.get(pair.assetIn) || null;
const assetOut = assetRegistry.get(pair.assetOut) || null;
const strategyConfig = strategyByPairId.get(pair.pairId) || null;
const priceRoute = routeByPairId.get(pair.pairId) || null;
const blockReasons = [];
if (!assetIn) blockReasons.push('asset_in_missing');
if (!assetOut) blockReasons.push('asset_out_missing');
if (assetIn && !Number.isInteger(assetIn.decimals)) blockReasons.push('asset_in_decimals_missing');
if (assetOut && !Number.isInteger(assetOut.decimals)) blockReasons.push('asset_out_decimals_missing');
if ((pairCanMake(pair) || pairCanTake(pair)) && !strategyConfig) {
blockReasons.push('pair_strategy_config_missing');
}
if ((pairCanMake(pair) || pairCanTake(pair)) && !priceRoute) {
blockReasons.push('price_route_missing');
}
if (strategyConfig && (!Number.isInteger(strategyConfig.edgeBps) || strategyConfig.edgeBps <= 0)) {
blockReasons.push('edge_bps_invalid');
}
if (strategyConfig && !(Number(strategyConfig.maxNotional) > 0)) {
blockReasons.push('max_notional_invalid');
}
const observeEnabled = pairCanObserve(pair);
const makerEnabled = pairCanMake(pair);
const takerEnabled = pairCanTake(pair);
const canTrade = (makerEnabled || takerEnabled) && blockReasons.length === 0;
return {
...pair,
key: pair.pairId,
assetIn,
assetOut,
asset_in: pair.assetIn,
asset_out: pair.assetOut,
asset_in_symbol: assetIn?.symbol || pair.assetIn,
asset_out_symbol: assetOut?.symbol || pair.assetOut,
strategyConfig,
priceRoute,
observeEnabled,
makerEnabled,
takerEnabled,
canTrade,
blockReason: blockReasons[0] || null,
blockReasons,
};
});
const observedPairs = pairs.filter((pair) => pair.observeEnabled);
const enabledPairKeys = new Set(observedPairs.map((pair) => pair.key));
const makerPairKeys = new Set(pairs.filter((pair) => pair.makerEnabled).map((pair) => pair.key));
const takerPairKeys = new Set(pairs.filter((pair) => pair.takerEnabled).map((pair) => pair.key));
const pairByKey = new Map(pairs.map((pair) => [pair.key, pair]));
const pairById = new Map(pairs.map((pair) => [pair.pairId, pair]));
const pairStrategyByPairKey = new Map(
pairs
.filter((pair) => pair.strategyConfig)
.map((pair) => [pair.key, pair.strategyConfig]),
);
const pairPriceRouteByPairKey = new Map(
pairs
.filter((pair) => pair.priceRoute)
.map((pair) => [pair.key, pair.priceRoute]),
);
const trackedAssets = assets.filter((asset) => asset.enabledForInventory);
const currentBtc = assetRegistry.get('nep141:nbtc.bridge.near') || trackedAssets.find((asset) => asset.symbol === 'BTC') || null;
const legacyBtc = assetRegistry.get('nep141:btc.omft.near') || null;
const currentEure = assetRegistry.get('nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near')
|| trackedAssets.find((asset) => asset.symbol === 'EURe')
|| null;
const preferredActivePair = pairByKey.get('nep141:nbtc.bridge.near->nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near')
|| observedPairs[0]
|| null;
const defaultTakerPair = pairByKey.get('nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near->nep141:nbtc.bridge.near')
|| pairs.find((pair) => pair.takerEnabled && pair.canTrade)
|| null;
const activeAssetIds = preferredActivePair?.assetIn && preferredActivePair?.assetOut
? [preferredActivePair.assetIn.assetId, preferredActivePair.assetOut.assetId]
: [];
const blockReason = observedPairs.length === 0
? 'no_enabled_pairs'
: trackedAssets.length === 0
? 'no_inventory_tracked_assets'
: null;
return {
ok: blockReason == null,
source: 'postgres',
loadedAt,
blockReason,
latestImportRun: normalizeAssetImportRunRow(latestImportRun),
assets,
assetRegistry,
trackedAssets,
trackedAssetIds: trackedAssets.map((asset) => asset.assetId),
tradingBtc: currentBtc,
tradingBtcAssets: [currentBtc, legacyBtc].filter(Boolean),
tradingEure: currentEure,
activePair: preferredActivePair?.key || null,
activeAssetIds,
pairs,
observedPairs,
enabledPairKeys,
makerPairKeys,
takerPairKeys,
pairByKey,
pairById,
pairStrategyByPairKey,
pairPriceRouteByPairKey,
defaultTakerPair,
tradingConfigLoaded: true,
requireDbTradingConfig: true,
};
}
function buildFailClosedTradingConfig(error) {
return {
ok: false,
source: 'postgres',
loadedAt: new Date().toISOString(),
blockReason: 'trading_config_unavailable',
error: error?.message || 'trading config unavailable',
latestImportRun: null,
assets: [],
assetRegistry: new Map(),
trackedAssets: [],
trackedAssetIds: [],
tradingBtc: null,
tradingBtcAssets: [],
tradingEure: null,
activePair: null,
activeAssetIds: [],
pairs: [],
observedPairs: [],
enabledPairKeys: new Set(),
makerPairKeys: new Set(),
takerPairKeys: new Set(),
pairByKey: new Map(),
pairById: new Map(),
pairStrategyByPairKey: new Map(),
pairPriceRouteByPairKey: new Map(),
defaultTakerPair: null,
tradingConfigLoaded: false,
requireDbTradingConfig: true,
};
}
export function summarizeTradingConfigSnapshot(snapshot) {
return {
ok: snapshot.ok,
source: snapshot.source,
loaded_at: snapshot.loadedAt,
block_reason: snapshot.blockReason || null,
error: snapshot.error || null,
latest_import: snapshot.latestImportRun || null,
asset_count: snapshot.assets?.length || 0,
tracked_asset_count: snapshot.trackedAssets?.length || 0,
enabled_pair_count: snapshot.observedPairs?.length || 0,
active_pair: snapshot.activePair || null,
pairs: (snapshot.pairs || []).map((pair) => ({
pair_id: pair.pairId,
pair: pair.key,
mode: pair.mode,
status: pair.status,
enabled: pair.enabled,
can_trade: pair.canTrade,
block_reason: pair.blockReason,
strategy_config_id: pair.strategyConfig?.configId || null,
strategy_config_version: pair.strategyConfig?.version || null,
edge_bps: pair.strategyConfig?.edgeBps ?? null,
max_notional: pair.strategyConfig?.maxNotional ?? null,
price_route_id: pair.priceRoute?.routeId || null,
})),
};
}
function normalizeTradingAssetRow(row) {
return {
assetId: row.asset_id,
asset_id: row.asset_id,
venue: row.venue,
symbol: row.symbol,
label: row.label || row.symbol,
decimals: Number(row.decimals),
blockchain: row.blockchain || null,
chain: row.chain || row.blockchain || null,
contractAddress: row.contract_address || null,
contract_address: row.contract_address || null,
latestPrice: row.latest_price == null ? null : String(row.latest_price),
latest_price: row.latest_price == null ? null : String(row.latest_price),
priceUpdatedAt: toIsoTimestamp(row.price_updated_at),
price_updated_at: toIsoTimestamp(row.price_updated_at),
supported: row.supported === true,
retiredAt: toIsoTimestamp(row.retired_at),
retired_at: toIsoTimestamp(row.retired_at),
enabledForInventory: row.enabled_for_inventory === true,
enabled_for_inventory: row.enabled_for_inventory === true,
role: row.role || null,
withdrawAddress: row.withdraw_address || '',
withdraw_address: row.withdraw_address || '',
rawPayload: row.raw_payload || {},
raw_payload: row.raw_payload || {},
updated_at: toIsoTimestamp(row.updated_at),
};
}
function normalizeAssetCatalogSummaryRow(row) {
return {
assetId: row.asset_id,
asset_id: row.asset_id,
venue: row.venue,
symbol: row.symbol,
label: row.label || row.symbol,
decimals: Number(row.decimals),
blockchain: row.blockchain || null,
chain: row.chain || row.blockchain || null,
contractAddress: row.contract_address || null,
contract_address: row.contract_address || null,
latestPrice: row.latest_price == null ? null : String(row.latest_price),
latest_price: row.latest_price == null ? null : String(row.latest_price),
priceUpdatedAt: toIsoTimestamp(row.price_updated_at),
price_updated_at: toIsoTimestamp(row.price_updated_at),
supported: row.supported === true,
retiredAt: toIsoTimestamp(row.retired_at),
retired_at: toIsoTimestamp(row.retired_at),
enabledForInventory: row.enabled_for_inventory === true,
enabled_for_inventory: row.enabled_for_inventory === true,
role: row.role || null,
withdrawAddress: row.withdraw_address || '',
withdraw_address: row.withdraw_address || '',
rawPayloadAvailable: row.raw_payload_available === true,
raw_payload_available: row.raw_payload_available === true,
updated_at: toIsoTimestamp(row.updated_at),
};
}
function normalizeTradingPairRow(row) {
return {
pairId: row.pair_id,
pair_id: row.pair_id,
venue: row.venue,
assetIn: row.asset_in,
assetOut: row.asset_out,
mode: row.mode,
enabled: row.enabled === true,
status: row.status,
created_at: toIsoTimestamp(row.created_at),
updated_at: toIsoTimestamp(row.updated_at),
};
}
function splitPairId(pairId) {
const parts = String(pairId || '').split('->');
if (parts.length !== 2 || !parts[0] || !parts[1]) return [null, null];
return parts;
}
function buildInitialPairStrategyConfig(pairId, {
edgeBps = null,
maxNotional = null,
minNotional = null,
slippageBps = null,
minDeadlineMs = null,
priceMaxAgeMs = null,
inventoryMaxAgeMs = null,
requestDefaultNotional = undefined,
requestMaxNotional = undefined,
requestMaxSlippageBps = undefined,
changedBy = 'operator',
reason = 'operator pair strategy config initialization',
} = {}) {
const baseConfig = buildSeedStrategyConfig(pairId, {
createdBy: changedBy,
reason,
});
return {
...baseConfig,
edgeBps: positiveIntegerOrDefault(edgeBps, baseConfig.edgeBps, 'edge_bps'),
maxNotional: positiveNumberStringOrDefault(maxNotional, baseConfig.maxNotional, 'max_notional'),
minNotional: nonNegativeNumberStringOrDefault(minNotional, baseConfig.minNotional, 'min_notional'),
slippageBps: nonNegativeIntegerOrDefault(slippageBps, baseConfig.slippageBps, 'slippage_bps'),
minDeadlineMs: positiveIntegerOrDefault(minDeadlineMs, baseConfig.minDeadlineMs, 'min_deadline_ms'),
priceMaxAgeMs: positiveIntegerOrDefault(priceMaxAgeMs, baseConfig.priceMaxAgeMs, 'price_max_age_ms'),
inventoryMaxAgeMs:
positiveIntegerOrDefault(inventoryMaxAgeMs, baseConfig.inventoryMaxAgeMs, 'inventory_max_age_ms'),
requestDefaultNotional:
nullablePositiveNumberStringOrDefault(
requestDefaultNotional,
baseConfig.requestDefaultNotional,
'request_default_notional',
),
requestMaxNotional:
nullablePositiveNumberStringOrDefault(
requestMaxNotional,
baseConfig.requestMaxNotional,
'request_max_notional',
),
requestMaxSlippageBps:
nullableNonNegativeIntegerOrDefault(
requestMaxSlippageBps,
baseConfig.requestMaxSlippageBps,
'request_max_slippage_bps',
),
};
}
function hasConfigOverride(value) {
return value != null && String(value).trim() !== '';
}
function positiveIntegerOrDefault(value, fallback, field) {
if (!hasConfigOverride(value)) return Number(fallback);
const next = Number(value);
if (!Number.isInteger(next) || next <= 0) throw new Error(`${field} must be a positive integer`);
return next;
}
function nonNegativeIntegerOrDefault(value, fallback, field) {
if (!hasConfigOverride(value)) return Number(fallback);
const next = Number(value);
if (!Number.isInteger(next) || next < 0) throw new Error(`${field} must be a non-negative integer`);
return next;
}
function positiveNumberStringOrDefault(value, fallback, field) {
if (!hasConfigOverride(value)) return String(fallback);
const next = String(value).trim();
if (!(Number(next) > 0)) throw new Error(`${field} must be greater than zero`);
return next;
}
function nonNegativeNumberStringOrDefault(value, fallback, field) {
if (!hasConfigOverride(value)) return String(fallback);
const next = String(value).trim();
if (!(Number(next) >= 0)) throw new Error(`${field} must be zero or greater`);
return next;
}
function nullablePositiveNumberStringOrDefault(value, fallback, field) {
if (value === undefined) return fallback == null ? null : positiveNumberStringOrDefault(fallback, '1', field);
return nullablePositiveNumberString(value, field);
}
function nullablePositiveNumberString(value, field) {
if (!hasConfigOverride(value)) return null;
return positiveNumberStringOrDefault(value, '1', field);
}
function nullableNonNegativeIntegerOrDefault(value, fallback, field) {
if (value === undefined) return fallback == null ? null : nonNegativeIntegerOrDefault(fallback, 0, field);
return nullableNonNegativeInteger(value, field);
}
function nullableNonNegativeInteger(value, field) {
if (!hasConfigOverride(value)) return null;
return nonNegativeIntegerOrDefault(value, 0, field);
}
function normalizeStrategyConfigRow(row) {
if (!row) return null;
return {
configId: row.config_id,
config_id: row.config_id,
pairId: row.pair_id,
pair_id: row.pair_id,
version: Number(row.version),
active: row.active === true,
edgeBps: Number(row.edge_bps),
edge_bps: Number(row.edge_bps),
maxNotional: String(row.max_notional),
max_notional: String(row.max_notional),
minNotional: String(row.min_notional ?? '0'),
min_notional: String(row.min_notional ?? '0'),
slippageBps: Number(row.slippage_bps ?? 0),
slippage_bps: Number(row.slippage_bps ?? 0),
minDeadlineMs: Number(row.min_deadline_ms),
min_deadline_ms: Number(row.min_deadline_ms),
priceMaxAgeMs: Number(row.price_max_age_ms),
price_max_age_ms: Number(row.price_max_age_ms),
inventoryMaxAgeMs: Number(row.inventory_max_age_ms),
inventory_max_age_ms: Number(row.inventory_max_age_ms),
requestDefaultNotional:
row.request_default_notional == null ? null : String(row.request_default_notional),
request_default_notional:
row.request_default_notional == null ? null : String(row.request_default_notional),
requestMaxNotional:
row.request_max_notional == null ? null : String(row.request_max_notional),
request_max_notional:
row.request_max_notional == null ? null : String(row.request_max_notional),
requestMaxSlippageBps:
row.request_max_slippage_bps == null ? null : Number(row.request_max_slippage_bps),
request_max_slippage_bps:
row.request_max_slippage_bps == null ? null : Number(row.request_max_slippage_bps),
created_at: toIsoTimestamp(row.created_at),
created_by: row.created_by || null,
reason: row.reason || null,
};
}
function normalizePriceRouteRow(row) {
if (!row) return null;
return {
routeId: row.route_id,
route_id: row.route_id,
pairId: row.pair_id,
pair_id: row.pair_id,
source: row.source,
baseAssetId: row.base_asset_id,
base_asset_id: row.base_asset_id,
quoteAssetId: row.quote_asset_id,
quote_asset_id: row.quote_asset_id,
routeConfig: row.route_config || {},
route_config: row.route_config || {},
maxAgeMs: Number(row.max_age_ms),
max_age_ms: Number(row.max_age_ms),
enabled: row.enabled === true,
};
}
function normalizeAssetImportRunRow(row) {
if (!row) return null;
return {
run_id: row.run_id,
source_url: row.source_url,
fetched_at: toIsoTimestamp(row.fetched_at),
status: row.status,
token_count: Number(row.token_count || 0),
added_count: Number(row.added_count || 0),
updated_count: Number(row.updated_count || 0),
unchanged_count: Number(row.unchanged_count || 0),
retired_count: Number(row.retired_count || 0),
raw_response_hash: row.raw_response_hash || null,
error: row.error || null,
};
}
function publicAssetImportRunSummary(run) {
const { raw_response: _rawResponse, ...publicRun } = run;
return publicRun;
}
async function seedKnownEnabledPairRuntimeConfig(pool, { now }) {
const pairResult = await pool.query(`SELECT * FROM ${TRADING_PAIRS_TABLE}`);
for (const row of pairResult.rows) {
const pair = normalizeTradingPairRow(row);
if (!pairCanMake(pair) && !pairCanTake(pair)) continue;
await enableInventoryForAssets(pool, {
assetIds: [pair.assetIn, pair.assetOut],
now,
});
const route = buildKnownPriceRouteForPair(pair);
if (route) await upsertSeedPriceRoute(pool, { route, now });
}
}
function buildKnownPriceRouteForPair(pair) {
const assets = new Set([pair?.assetIn, pair?.assetOut]);
if (assets.has(CURRENT_NBTC_ASSET_ID) && assets.has(CURRENT_USDC_ASSET_ID)) {
return buildBtcUsdcPriceRoute(pair.pairId);
}
return null;
}
async function enableInventoryForAssets(pool, { assetIds, now }) {
const uniqueAssetIds = [...new Set(assetIds.filter(Boolean))];
if (!uniqueAssetIds.length) return;
await pool.query(
`
UPDATE ${TRADING_ASSETS_TABLE}
SET enabled_for_inventory = true,
updated_at = $2
WHERE asset_id = ANY($1::text[])
`,
[uniqueAssetIds, now],
);
}
async function upsertSeedAsset(pool, { asset, now }) {
await pool.query(
`
INSERT INTO ${TRADING_ASSETS_TABLE} (
asset_id,
venue,
symbol,
label,
decimals,
blockchain,
chain,
contract_address,
latest_price,
price_updated_at,
supported,
retired_at,
enabled_for_inventory,
role,
withdraw_address,
raw_payload,
last_supported_at,
updated_at
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,NULL,$12,$13,$14,$15::jsonb,$16,$16)
ON CONFLICT (asset_id) DO UPDATE SET
venue = EXCLUDED.venue,
symbol = EXCLUDED.symbol,
label = EXCLUDED.label,
decimals = EXCLUDED.decimals,
blockchain = EXCLUDED.blockchain,
chain = EXCLUDED.chain,
contract_address = COALESCE(${TRADING_ASSETS_TABLE}.contract_address, EXCLUDED.contract_address),
supported = ${TRADING_ASSETS_TABLE}.supported OR EXCLUDED.supported,
enabled_for_inventory = ${TRADING_ASSETS_TABLE}.enabled_for_inventory OR EXCLUDED.enabled_for_inventory,
role = COALESCE(${TRADING_ASSETS_TABLE}.role, EXCLUDED.role),
withdraw_address = COALESCE(NULLIF(${TRADING_ASSETS_TABLE}.withdraw_address, ''), EXCLUDED.withdraw_address),
raw_payload = CASE
WHEN ${TRADING_ASSETS_TABLE}.raw_payload = '{}'::jsonb THEN EXCLUDED.raw_payload
ELSE ${TRADING_ASSETS_TABLE}.raw_payload
END,
last_supported_at = COALESCE(${TRADING_ASSETS_TABLE}.last_supported_at, EXCLUDED.last_supported_at),
updated_at = EXCLUDED.updated_at
`,
[
asset.assetId,
asset.venue,
asset.symbol,
asset.label,
asset.decimals,
asset.blockchain,
asset.chain || asset.blockchain,
asset.contractAddress,
asset.latestPrice,
asset.priceUpdatedAt,
asset.supported,
asset.enabledForInventory,
asset.role,
asset.withdrawAddress || '',
JSON.stringify(asset.rawPayload || {}),
now,
],
);
}
async function upsertSeedPair(pool, { pair, now, preserveRuntimeState = false }) {
const conflictUpdate = preserveRuntimeState
? `
venue = EXCLUDED.venue,
asset_in = EXCLUDED.asset_in,
asset_out = EXCLUDED.asset_out,
mode = ${TRADING_PAIRS_TABLE}.mode,
enabled = ${TRADING_PAIRS_TABLE}.enabled,
status = ${TRADING_PAIRS_TABLE}.status,
updated_at = EXCLUDED.updated_at
`
: `
venue = EXCLUDED.venue,
asset_in = EXCLUDED.asset_in,
asset_out = EXCLUDED.asset_out,
mode = EXCLUDED.mode,
enabled = EXCLUDED.enabled,
status = EXCLUDED.status,
updated_at = EXCLUDED.updated_at
`;
await pool.query(
`
INSERT INTO ${TRADING_PAIRS_TABLE} (
pair_id,
venue,
asset_in,
asset_out,
mode,
enabled,
status,
created_at,
updated_at
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$8)
ON CONFLICT (pair_id) DO UPDATE SET
${conflictUpdate}
`,
[
pair.pairId,
pair.venue,
pair.assetIn,
pair.assetOut,
pair.mode,
pair.enabled,
pair.status,
now,
],
);
}
async function upsertSeedStrategyConfig(pool, { config }) {
await insertPairStrategyConfig(pool, { config, active: config.active !== false });
}
async function insertPairStrategyConfig(pool, { config, active = true }) {
await pool.query(
`
INSERT INTO ${PAIR_STRATEGY_CONFIGS_TABLE} (
config_id,
pair_id,
version,
active,
edge_bps,
max_notional,
min_notional,
slippage_bps,
min_deadline_ms,
price_max_age_ms,
inventory_max_age_ms,
request_default_notional,
request_max_notional,
request_max_slippage_bps,
created_by,
reason
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)
ON CONFLICT (config_id) DO NOTHING
`,
[
config.configId,
config.pairId,
config.version,
active,
config.edgeBps,
config.maxNotional,
config.minNotional,
config.slippageBps,
config.minDeadlineMs,
config.priceMaxAgeMs,
config.inventoryMaxAgeMs,
config.requestDefaultNotional,
config.requestMaxNotional,
config.requestMaxSlippageBps,
config.createdBy,
config.reason,
],
);
}
async function upsertSeedPriceRoute(pool, { route, now }) {
await pool.query(
`
INSERT INTO ${PAIR_PRICE_ROUTES_TABLE} (
route_id,
pair_id,
source,
base_asset_id,
quote_asset_id,
route_config,
max_age_ms,
enabled,
created_at,
updated_at
) VALUES ($1,$2,$3,$4,$5,$6::jsonb,$7,$8,$9,$9)
ON CONFLICT (route_id) DO UPDATE SET
source = EXCLUDED.source,
base_asset_id = EXCLUDED.base_asset_id,
quote_asset_id = EXCLUDED.quote_asset_id,
route_config = EXCLUDED.route_config,
max_age_ms = EXCLUDED.max_age_ms,
enabled = ${PAIR_PRICE_ROUTES_TABLE}.enabled,
updated_at = EXCLUDED.updated_at
`,
[
route.routeId,
route.pairId,
route.source,
route.baseAssetId,
route.quoteAssetId,
JSON.stringify(route.routeConfig || {}),
route.maxAgeMs,
route.enabled,
now,
],
);
}
async function loadTradingAssetsById(pool) {
const result = await pool.query(`SELECT * FROM ${TRADING_ASSETS_TABLE}`);
return new Map(result.rows.map((row) => [row.asset_id, normalizeTradingAssetRow(row)]));
}
async function upsertImportedAsset(pool, { asset, fetchedAt }) {
await pool.query(
`
INSERT INTO ${TRADING_ASSETS_TABLE} (
asset_id,
venue,
symbol,
label,
decimals,
blockchain,
chain,
contract_address,
latest_price,
price_updated_at,
supported,
retired_at,
enabled_for_inventory,
raw_payload,
last_supported_at,
updated_at
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,true,NULL,false,$11::jsonb,$12,$12)
ON CONFLICT (asset_id) DO UPDATE SET
venue = EXCLUDED.venue,
symbol = EXCLUDED.symbol,
label = EXCLUDED.label,
decimals = EXCLUDED.decimals,
blockchain = EXCLUDED.blockchain,
chain = EXCLUDED.chain,
contract_address = EXCLUDED.contract_address,
latest_price = EXCLUDED.latest_price,
price_updated_at = EXCLUDED.price_updated_at,
supported = true,
retired_at = NULL,
enabled_for_inventory = ${TRADING_ASSETS_TABLE}.enabled_for_inventory,
raw_payload = EXCLUDED.raw_payload,
last_supported_at = EXCLUDED.last_supported_at,
updated_at = EXCLUDED.updated_at
`,
[
asset.assetId,
asset.venue,
asset.symbol,
asset.label,
asset.decimals,
asset.blockchain,
asset.chain || asset.blockchain,
asset.contractAddress,
asset.latestPrice,
asset.priceUpdatedAt,
JSON.stringify(asset.rawPayload || {}),
fetchedAt,
],
);
}
async function insertAssetImportRun(pool, run) {
await pool.query(
`
INSERT INTO ${SUPPORTED_ASSET_IMPORT_RUNS_TABLE} (
run_id,
source_url,
fetched_at,
status,
token_count,
added_count,
updated_count,
unchanged_count,
retired_count,
raw_response_hash,
error,
raw_response
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb)
ON CONFLICT (run_id) DO UPDATE SET
status = EXCLUDED.status,
token_count = EXCLUDED.token_count,
added_count = EXCLUDED.added_count,
updated_count = EXCLUDED.updated_count,
unchanged_count = EXCLUDED.unchanged_count,
retired_count = EXCLUDED.retired_count,
raw_response_hash = EXCLUDED.raw_response_hash,
error = EXCLUDED.error,
raw_response = EXCLUDED.raw_response
`,
[
run.run_id,
run.source_url,
run.fetched_at,
run.status,
run.token_count,
run.added_count,
run.updated_count,
run.unchanged_count,
run.retired_count,
run.raw_response_hash,
run.error,
run.raw_response == null ? null : JSON.stringify(run.raw_response),
],
);
}
async function insertConfigAuditLog(pool, {
entityType,
entityId,
action,
oldValue = null,
newValue = null,
changedBy,
reason,
}) {
await pool.query(
`
INSERT INTO ${PAIR_CONFIG_AUDIT_LOG_TABLE} (
audit_id,
entity_type,
entity_id,
action,
old_value,
new_value,
changed_by,
reason
) VALUES ($1,$2,$3,$4,$5::jsonb,$6::jsonb,$7,$8)
`,
[
`audit:${Date.now()}:${Math.random().toString(16).slice(2)}`,
entityType,
entityId,
action,
oldValue == null ? null : JSON.stringify(oldValue),
newValue == null ? null : JSON.stringify(newValue),
changedBy,
reason,
],
);
}
function importedAssetChanged(previous, next) {
return (
previous.symbol !== next.symbol
|| previous.label !== next.label
|| previous.decimals !== next.decimals
|| previous.blockchain !== next.blockchain
|| previous.contractAddress !== next.contractAddress
|| previous.latestPrice !== next.latestPrice
|| previous.priceUpdatedAt !== next.priceUpdatedAt
|| previous.supported !== true
|| previous.retiredAt != null
);
}
export async function insertHistoryEvent(pool, { table, topic, event, record }) {
await pool.query(
`
INSERT INTO ${table} (
event_id,
topic,
venue,
source,
event_type,
observed_at,
ingested_at,
quote_id,
pair,
decision_key,
payload,
raw
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12::jsonb
)
ON CONFLICT (event_id) DO NOTHING
`,
[
event.event_id,
topic,
event.venue,
event.source,
event.event_type,
event.observed_at,
event.ingested_at,
record.quote_id,
record.pair,
record.decision_key,
JSON.stringify(event.payload),
event.raw ? JSON.stringify(event.raw) : null,
],
);
}
export async function insertEnvironmentStatusChange(pool, { topic, event, record }) {
const fingerprint = event.payload?.status_fingerprint || null;
const environmentKey = event.payload?.environment_key || record.decision_key || null;
const result = await pool.query(
`
WITH latest AS (
SELECT payload->>'status_fingerprint' AS status_fingerprint
FROM environment_status_events
WHERE decision_key = $10
ORDER BY COALESCE(observed_at, ingested_at) DESC, ingested_at DESC
LIMIT 1
)
INSERT INTO environment_status_events (
event_id,
topic,
venue,
source,
event_type,
observed_at,
ingested_at,
quote_id,
pair,
decision_key,
payload,
raw
)
SELECT $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12::jsonb
WHERE NOT EXISTS (
SELECT 1 FROM latest WHERE status_fingerprint = $13
)
ON CONFLICT (event_id) DO NOTHING
RETURNING event_id
`,
[
event.event_id,
topic,
event.venue,
event.source,
event.event_type,
event.observed_at,
event.ingested_at,
record.quote_id,
record.pair,
environmentKey,
JSON.stringify(event.payload),
event.raw ? JSON.stringify(event.raw) : null,
fingerprint,
],
);
return {
inserted: result.rowCount > 0,
status_fingerprint: fingerprint,
environment_key: environmentKey,
};
}
export async function loadPortfolioMetricInputs(pool, {
btcAsset = null,
btcAssets = null,
eureAsset = null,
trackedAssets = [],
} = {}) {
const effectiveBtcAssets = normalizeBtcAssets({ btcAsset, btcAssets });
const [currentInventory, currentPrice, currentPriceEvents, commandAggregate, resultAggregate] = await Promise.all([
loadLatestEventPayload(pool, 'intent_inventory_snapshots'),
loadLatestEventPayload(
pool,
'market_price_events',
"WHERE COALESCE(payload->>'eure_per_btc', '') <> '' ORDER BY COALESCE(observed_at, ingested_at) DESC LIMIT 1",
),
loadLatestMarketPricePayloadsByRoute(pool),
pool.query(`
SELECT
MIN(ingested_at) AS first_command_at,
COUNT(*)::INT AS command_count
FROM execute_trade_commands
`),
pool.query(`
SELECT COUNT(*)::INT AS result_count
FROM trade_execution_results
`),
]);
const firstCommandAt = commandAggregate.rows[0]?.first_command_at || null;
const commandCount = Number(commandAggregate.rows[0]?.command_count || 0);
const resultCount = Number(resultAggregate.rows[0]?.result_count || 0);
const valuationAssets = buildCashEquivalentValuationAssets({
trackedAssets,
btcAsset: effectiveBtcAssets[0],
btcAssets: effectiveBtcAssets,
eureAsset,
priceEvents: currentPriceEvents.map((entry) => entry.payload),
});
if (!firstCommandAt) {
return {
currentInventory,
currentPrice,
currentPriceEvents,
valuationAssets,
baseline: null,
commandCount,
resultCount,
};
}
const baselineInventory = await loadLatestEventPayload(
pool,
'intent_inventory_snapshots',
'WHERE ingested_at <= $1 ORDER BY ingested_at DESC LIMIT 1',
[firstCommandAt],
);
const baselinePrice = await loadNearestPricePayload(pool, baselineInventory?.ingested_at || firstCommandAt);
const externalFlows = (
baselineInventory
&& baselinePrice
&& effectiveBtcAssets.length
&& eureAsset?.assetId
)
? await loadExternalAssetFlowsSince(pool, {
since: firstCommandAt,
btcAsset: effectiveBtcAssets[0],
btcAssets: effectiveBtcAssets,
eureAsset,
valuationAssets,
})
: [];
return {
currentInventory,
currentPrice,
currentPriceEvents,
valuationAssets,
baseline: baselineInventory && baselinePrice ? {
anchor: 'latest_inventory_before_first_command',
command_at: new Date(firstCommandAt).toISOString(),
inventory: baselineInventory.payload,
price: baselinePrice.payload,
} : null,
externalFlows,
commandCount,
resultCount,
};
}
async function loadLatestMarketPricePayloadsByRoute(pool) {
const result = await pool.query(`
SELECT DISTINCT ON (payload->>'price_route_id')
observed_at,
ingested_at,
payload
FROM market_price_events
WHERE COALESCE(payload->>'price_route_id', '') <> ''
ORDER BY payload->>'price_route_id', COALESCE(observed_at, ingested_at) DESC
`);
return result.rows.map((row) => ({
observed_at: toIsoTimestamp(row.observed_at),
ingested_at: toIsoTimestamp(row.ingested_at),
payload: {
...(row.payload || {}),
observed_at: row.payload?.observed_at || toIsoTimestamp(row.observed_at),
ingested_at: row.payload?.ingested_at || toIsoTimestamp(row.ingested_at),
},
}));
}
export async function upsertPortfolioMetric(pool, {
metricId,
computedAt,
baselineAnchorAt = null,
baselineStatus,
payload,
}) {
await pool.query(
`
INSERT INTO ${PORTFOLIO_METRICS_TABLE} (
metric_id,
computed_at,
baseline_anchor_at,
baseline_status,
payload
) VALUES ($1, $2, $3, $4, $5::jsonb)
ON CONFLICT (metric_id) DO UPDATE SET
computed_at = EXCLUDED.computed_at,
baseline_anchor_at = EXCLUDED.baseline_anchor_at,
baseline_status = EXCLUDED.baseline_status,
payload = EXCLUDED.payload
`,
[
metricId,
computedAt,
baselineAnchorAt,
baselineStatus,
JSON.stringify(payload),
],
);
}
export async function loadLatestPortfolioMetric(pool) {
const result = await pool.query(`
SELECT metric_id, computed_at, baseline_anchor_at, baseline_status, payload
FROM ${PORTFOLIO_METRICS_TABLE}
ORDER BY computed_at DESC
LIMIT 1
`);
if (!result.rows[0]) return null;
return normalizePortfolioMetricRow(result.rows[0]);
}
export async function claimNotificationDelivery(pool, {
notificationKey,
notificationType,
sourceKind,
sourceId = null,
payload = {},
}) {
if (!notificationKey) throw new Error('notificationKey is required');
if (!notificationType) throw new Error('notificationType is required');
if (!sourceKind) throw new Error('sourceKind is required');
const result = await pool.query(
`
INSERT INTO notification_deliveries (
notification_key,
notification_type,
source_kind,
source_id,
status,
attempt_count,
payload,
response,
error
) VALUES ($1, $2, $3, $4, 'pending', 1, $5::jsonb, NULL, NULL)
ON CONFLICT (notification_key) DO UPDATE SET
status = 'pending',
attempt_count = notification_deliveries.attempt_count + 1,
last_attempt_at = NOW(),
payload = EXCLUDED.payload,
response = NULL,
error = NULL
WHERE notification_deliveries.status <> 'delivered'
RETURNING notification_key
`,
[
notificationKey,
notificationType,
sourceKind,
sourceId,
JSON.stringify(payload || {}),
],
);
return result.rowCount > 0;
}
export async function finishNotificationDelivery(pool, {
notificationKey,
ok,
response = null,
error = null,
}) {
if (!notificationKey) throw new Error('notificationKey is required');
await pool.query(
`
UPDATE notification_deliveries
SET
status = $2,
delivered_at = CASE WHEN $2 = 'delivered' THEN NOW() ELSE delivered_at END,
last_attempt_at = NOW(),
response = $3::jsonb,
error = $4::jsonb
WHERE notification_key = $1
`,
[
notificationKey,
ok ? 'delivered' : 'failed',
response ? JSON.stringify(response) : null,
error ? JSON.stringify(error) : null,
],
);
}
export async function refreshQuoteOutcomes(pool, {
btcAsset = null,
eureAsset = null,
now = Date.now(),
submissionLimit = 1000,
inventoryLimit = 5000,
} = {}) {
if (!btcAsset?.assetId || !eureAsset?.assetId) return [];
const safeSubmissionLimit = Math.max(1, Number(submissionLimit) || 1000);
const safeInventoryLimit = Math.max(1, Number(inventoryLimit) || 5000);
const submissionsResult = await pool.query(
`
SELECT event_id, observed_at, ingested_at, quote_id, payload
FROM (
SELECT event_id, observed_at, ingested_at, quote_id, payload
FROM trade_execution_results
WHERE payload->>'status' = 'submitted'
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT $1
) recent_submissions
ORDER BY COALESCE(observed_at, ingested_at) ASC
`,
[safeSubmissionLimit],
);
if (!submissionsResult.rows.length) return [];
const quoteIds = [...new Set(submissionsResult.rows.map((row) => row.quote_id).filter(Boolean))];
if (!quoteIds.length) return [];
const [
commandsResult,
decisionsResult,
inventoryResult,
] = await Promise.all([
pool.query(`
SELECT event_id, observed_at, ingested_at, quote_id, payload
FROM execute_trade_commands
WHERE quote_id = ANY($1::text[])
ORDER BY COALESCE(observed_at, ingested_at) ASC
`, [quoteIds]),
pool.query(`
SELECT event_id, observed_at, ingested_at, quote_id, payload
FROM trade_decisions
WHERE quote_id = ANY($1::text[])
ORDER BY COALESCE(observed_at, ingested_at) ASC
`, [quoteIds]),
pool.query(`
SELECT event_id, observed_at, ingested_at, quote_id, payload
FROM (
SELECT event_id, observed_at, ingested_at, quote_id, payload
FROM intent_inventory_snapshots
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT $1
) recent_inventory_snapshots
ORDER BY COALESCE(observed_at, ingested_at) ASC
`, [safeInventoryLimit]),
]);
const records = deriveQuoteOutcomeRecords({
submissions: submissionsResult.rows,
commands: commandsResult.rows,
decisions: decisionsResult.rows,
inventorySnapshots: inventoryResult.rows,
btcAsset,
eureAsset,
now,
});
if (!records.length) return [];
const computedAt = new Date(
typeof now === 'number' ? now : Date.parse(now),
).toISOString();
for (const record of records) {
await upsertQuoteOutcome(pool, {
...record,
computedAt,
});
}
return records;
}
export async function upsertQuoteOutcome(pool, {
quote_id,
decision_id = null,
command_id = null,
execution_result_status,
execution_result_code = null,
submitted_at = null,
command_at = null,
outcome_status,
outcome_observed_at = null,
outcome_source,
attribution_status,
attribution_method = null,
attributed_inventory_delta = null,
computedAt,
payload,
}) {
await pool.query(
`
INSERT INTO ${QUOTE_OUTCOMES_TABLE} (
quote_id,
decision_id,
command_id,
execution_result_status,
execution_result_code,
submitted_at,
command_at,
outcome_status,
outcome_observed_at,
outcome_source,
attribution_status,
attribution_method,
attributed_inventory_delta,
computed_at,
payload
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13::jsonb,$14,$15::jsonb
)
ON CONFLICT (quote_id) DO UPDATE SET
decision_id = EXCLUDED.decision_id,
command_id = EXCLUDED.command_id,
execution_result_status = EXCLUDED.execution_result_status,
execution_result_code = EXCLUDED.execution_result_code,
submitted_at = EXCLUDED.submitted_at,
command_at = EXCLUDED.command_at,
outcome_status = EXCLUDED.outcome_status,
outcome_observed_at = EXCLUDED.outcome_observed_at,
outcome_source = EXCLUDED.outcome_source,
attribution_status = EXCLUDED.attribution_status,
attribution_method = EXCLUDED.attribution_method,
attributed_inventory_delta = EXCLUDED.attributed_inventory_delta,
computed_at = EXCLUDED.computed_at,
payload = EXCLUDED.payload
`,
[
quote_id,
decision_id,
command_id,
execution_result_status,
execution_result_code,
submitted_at,
command_at,
outcome_status,
outcome_observed_at,
outcome_source,
attribution_status,
attribution_method,
attributed_inventory_delta ? JSON.stringify(attributed_inventory_delta) : null,
computedAt,
JSON.stringify(payload || {}),
],
);
}
export async function loadRecentQuoteOutcomes(pool, { limit = 200 } = {}) {
const result = await pool.query(
`
SELECT
quote_id,
decision_id,
command_id,
execution_result_status,
execution_result_code,
submitted_at,
command_at,
outcome_status,
outcome_observed_at,
outcome_source,
attribution_status,
attribution_method,
attributed_inventory_delta,
computed_at,
payload
FROM ${QUOTE_OUTCOMES_TABLE}
ORDER BY
CASE outcome_status
WHEN 'completed' THEN 0
WHEN 'not_filled' THEN 1
ELSE 2
END,
COALESCE(outcome_observed_at, submitted_at, computed_at) DESC
LIMIT $1
`,
[Math.max(1, Number(limit) || 200)],
);
return result.rows.map(normalizeQuoteOutcomeRow);
}
export async function loadIntentRequestPreflightByIdOrKey(pool, {
requestId = null,
idempotencyKey = null,
} = {}) {
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM intent_request_preflights
WHERE ($1::text IS NOT NULL AND payload->>'request_id' = $1)
OR ($2::text IS NOT NULL AND payload->>'idempotency_key' = $2)
ORDER BY
COALESCE(observed_at, ingested_at) DESC,
CASE payload->>'status'
WHEN 'accepted_by_relay' THEN 0
WHEN 'failed' THEN 1
WHEN 'blocked' THEN 2
WHEN 'submit_requested' THEN 3
ELSE 4
END
LIMIT 1
`,
[requestId, idempotencyKey],
);
return normalizeEventPayloadRow(result.rows[0])?.payload || null;
}
export async function loadLatestIntentRequestSubmission(pool, { requestId } = {}) {
if (!requestId) return null;
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM intent_request_submission_results
WHERE payload->>'request_id' = $1
ORDER BY
COALESCE(observed_at, ingested_at) DESC,
CASE payload->>'status'
WHEN 'accepted_by_relay' THEN 0
WHEN 'failed' THEN 1
WHEN 'blocked' THEN 2
WHEN 'submit_requested' THEN 3
ELSE 4
END
LIMIT 1
`,
[requestId],
);
return normalizeEventPayloadRow(result.rows[0])?.payload || null;
}
export async function loadIntentRequestSubmissionsForStatusRefresh(pool, {
limit = 20,
} = {}) {
const result = await pool.query(
`
WITH latest_submissions AS (
SELECT DISTINCT ON (payload->>'request_id')
observed_at, ingested_at, payload
FROM intent_request_submission_results
WHERE COALESCE(payload->>'request_id', '') <> ''
ORDER BY
payload->>'request_id',
COALESCE(observed_at, ingested_at) DESC,
CASE payload->>'status'
WHEN 'accepted_by_relay' THEN 0
WHEN 'failed' THEN 1
WHEN 'blocked' THEN 2
WHEN 'submit_requested' THEN 3
ELSE 4
END
)
SELECT observed_at, ingested_at, payload
FROM latest_submissions
WHERE payload->>'status' = 'accepted_by_relay'
AND COALESCE(payload->>'intent_hash', '') <> ''
AND COALESCE(payload->>'relay_status', '') NOT IN ('SETTLED', 'NOT_FOUND_OR_NOT_VALID')
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT $1
`,
[Math.max(1, Number(limit) || 20)],
);
return result.rows
.map((row) => normalizeIntentRequestSubmissionPayload(normalizeEventPayloadRow(row)?.payload || null))
.filter(Boolean);
}
export async function refreshIntentRequestOutcomes(pool, {
btcAsset = null,
eureAsset = null,
now = Date.now(),
preflightLimit = 100,
submissionLimit = 500,
inventoryLimit = 5000,
} = {}) {
if (!btcAsset?.assetId || !eureAsset?.assetId) return [];
const safePreflightLimit = Math.max(1, Number(preflightLimit) || 100);
const safeSubmissionLimit = Math.max(1, Number(submissionLimit) || 500);
const safeInventoryLimit = Math.max(1, Number(inventoryLimit) || 5000);
const preflightResult = await loadIntentRequestPreflightRefreshCandidates(pool, {
limit: safePreflightLimit,
});
if (!preflightResult.rows.length) return [];
const requestIds = [
...new Set(preflightResult.rows
.map((row) => row.payload?.request_id)
.filter(Boolean)),
];
if (!requestIds.length) return [];
const submissions = await loadIntentRequestSubmissionsForRefresh(pool, {
requestIds,
limit: safeSubmissionLimit,
});
const inventorySnapshots = await loadIntentInventorySnapshotsForRequestRefresh(pool, {
submissions: submissions.rows,
limit: safeInventoryLimit,
});
const records = deriveIntentRequestOutcomeRecords({
preflights: preflightResult.rows,
submissions: submissions.rows,
inventorySnapshots: inventorySnapshots.rows,
btcAsset,
eureAsset,
now,
});
if (!records.length) return [];
const computedAt = new Date(
typeof now === 'number' ? now : Date.parse(now),
).toISOString();
for (const record of records) {
await upsertIntentRequestOutcome(pool, {
...record,
computedAt,
});
}
return records;
}
async function loadIntentRequestPreflightRefreshCandidates(pool, { limit }) {
return pool.query(
`
WITH latest_preflights AS (
SELECT DISTINCT ON (payload->>'request_id')
event_id,
observed_at,
ingested_at,
payload
FROM intent_request_preflights
WHERE COALESCE(payload->>'request_id', '') <> ''
ORDER BY payload->>'request_id', COALESCE(observed_at, ingested_at) DESC
), latest_submissions AS (
SELECT DISTINCT ON (payload->>'request_id')
payload->>'request_id' AS request_id,
observed_at,
ingested_at,
payload
FROM intent_request_submission_results
WHERE COALESCE(payload->>'request_id', '') <> ''
ORDER BY
payload->>'request_id',
COALESCE(observed_at, ingested_at) DESC,
CASE payload->>'status'
WHEN 'accepted_by_relay' THEN 0
WHEN 'failed' THEN 1
WHEN 'blocked' THEN 2
WHEN 'submit_requested' THEN 3
ELSE 4
END
), refresh_candidates AS (
SELECT
p.event_id,
p.observed_at,
p.ingested_at,
p.payload,
COALESCE(
s.observed_at,
s.ingested_at,
p.observed_at,
p.ingested_at
) AS refresh_sort_at
FROM latest_preflights p
LEFT JOIN latest_submissions s
ON s.request_id = p.payload->>'request_id'
LEFT JOIN ${INTENT_REQUEST_OUTCOMES_TABLE} o
ON o.request_id = p.payload->>'request_id'
WHERE o.request_id IS NULL
OR o.outcome_status = ANY($1::text[])
OR COALESCE(
s.observed_at,
s.ingested_at,
p.observed_at,
p.ingested_at
) > o.computed_at
ORDER BY refresh_sort_at DESC
LIMIT $2
)
SELECT event_id, observed_at, ingested_at, payload
FROM refresh_candidates
ORDER BY COALESCE(observed_at, ingested_at) ASC
`,
[REFRESHABLE_INTENT_REQUEST_OUTCOME_STATUSES, limit],
);
}
async function loadIntentRequestSubmissionsForRefresh(pool, { requestIds, limit }) {
return pool.query(
`
SELECT event_id, observed_at, ingested_at, payload
FROM intent_request_submission_results
WHERE payload->>'request_id' = ANY($1::text[])
ORDER BY COALESCE(observed_at, ingested_at) ASC
LIMIT $2
`,
[requestIds, limit],
);
}
async function loadIntentInventorySnapshotsForRequestRefresh(pool, {
submissions,
limit,
}) {
const anchorAt = earliestIntentRequestInventoryAnchor({
submissions,
});
if (!anchorAt) return { rows: [] };
return pool.query(
`
WITH previous_snapshot AS (
SELECT event_id, observed_at, ingested_at, quote_id, payload, COALESCE(observed_at, ingested_at) AS sort_at
FROM intent_inventory_snapshots
WHERE COALESCE(observed_at, ingested_at) < $1
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT 1
), following_snapshots AS (
SELECT event_id, observed_at, ingested_at, quote_id, payload, COALESCE(observed_at, ingested_at) AS sort_at
FROM intent_inventory_snapshots
WHERE COALESCE(observed_at, ingested_at) >= $1
ORDER BY COALESCE(observed_at, ingested_at) ASC
LIMIT $2
), bounded_snapshots AS (
SELECT event_id, observed_at, ingested_at, quote_id, payload, sort_at
FROM previous_snapshot
UNION ALL
SELECT event_id, observed_at, ingested_at, quote_id, payload, sort_at
FROM following_snapshots
)
SELECT event_id, observed_at, ingested_at, quote_id, payload
FROM bounded_snapshots
ORDER BY sort_at ASC
`,
[anchorAt, limit],
);
}
function earliestIntentRequestInventoryAnchor({ submissions = [] } = {}) {
const anchors = submissions
.map((row) => row.payload?.submitted_at || row.observed_at || row.ingested_at)
.map((value) => {
const timestamp = timestampValue(value);
return Number.isFinite(timestamp) ? timestamp : null;
})
.filter((value) => value != null)
.sort((left, right) => left - right);
return anchors.length ? new Date(anchors[0]).toISOString() : null;
}
export async function upsertIntentRequestOutcome(pool, {
request_id,
idempotency_key,
submission_id = null,
intent_hash = null,
submission_status = null,
relay_status = null,
submitted_at = null,
outcome_status,
outcome_observed_at = null,
outcome_source,
outcome_reason,
attribution_status,
attribution_method = null,
attributed_inventory_delta = null,
computedAt,
payload,
}) {
await pool.query(
`
INSERT INTO ${INTENT_REQUEST_OUTCOMES_TABLE} (
request_id,
idempotency_key,
submission_id,
intent_hash,
submission_status,
relay_status,
submitted_at,
outcome_status,
outcome_observed_at,
outcome_source,
outcome_reason,
attribution_status,
attribution_method,
attributed_inventory_delta,
computed_at,
payload
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14::jsonb,$15,$16::jsonb
)
ON CONFLICT (request_id) DO UPDATE SET
idempotency_key = EXCLUDED.idempotency_key,
submission_id = EXCLUDED.submission_id,
intent_hash = EXCLUDED.intent_hash,
submission_status = EXCLUDED.submission_status,
relay_status = EXCLUDED.relay_status,
submitted_at = EXCLUDED.submitted_at,
outcome_status = EXCLUDED.outcome_status,
outcome_observed_at = EXCLUDED.outcome_observed_at,
outcome_source = EXCLUDED.outcome_source,
outcome_reason = EXCLUDED.outcome_reason,
attribution_status = EXCLUDED.attribution_status,
attribution_method = EXCLUDED.attribution_method,
attributed_inventory_delta = EXCLUDED.attributed_inventory_delta,
computed_at = EXCLUDED.computed_at,
payload = EXCLUDED.payload
`,
[
request_id,
idempotency_key,
submission_id,
intent_hash,
submission_status,
relay_status,
submitted_at,
outcome_status,
outcome_observed_at,
outcome_source,
outcome_reason,
attribution_status,
attribution_method,
attributed_inventory_delta ? JSON.stringify(attributed_inventory_delta) : null,
computedAt,
JSON.stringify(payload || {}),
],
);
}
export async function loadRecentIntentRequests(pool, {
limit = 20,
btcAsset = null,
eureAsset = null,
now = Date.now(),
refreshOutcomes = true,
} = {}) {
if (refreshOutcomes && btcAsset?.assetId && eureAsset?.assetId) {
await refreshIntentRequestOutcomes(pool, { btcAsset, eureAsset, now }).catch(() => []);
}
const result = await pool.query(
`
WITH latest_preflights AS (
SELECT DISTINCT ON (payload->>'request_id')
observed_at AS preflight_observed_at,
ingested_at AS preflight_ingested_at,
payload AS preflight_payload
FROM intent_request_preflights
WHERE COALESCE(payload->>'request_id', '') <> ''
ORDER BY payload->>'request_id', COALESCE(observed_at, ingested_at) DESC
), latest_submissions AS (
SELECT DISTINCT ON (payload->>'request_id')
observed_at AS submission_observed_at,
ingested_at AS submission_ingested_at,
payload AS submission_payload
FROM intent_request_submission_results
WHERE COALESCE(payload->>'request_id', '') <> ''
ORDER BY
payload->>'request_id',
COALESCE(observed_at, ingested_at) DESC,
CASE payload->>'status'
WHEN 'accepted_by_relay' THEN 0
WHEN 'failed' THEN 1
WHEN 'blocked' THEN 2
WHEN 'submit_requested' THEN 3
ELSE 4
END
)
SELECT
p.preflight_observed_at,
p.preflight_ingested_at,
p.preflight_payload,
s.submission_observed_at,
s.submission_ingested_at,
s.submission_payload,
o.outcome_observed_at,
o.computed_at AS outcome_computed_at,
o.payload AS outcome_payload
FROM latest_preflights p
LEFT JOIN latest_submissions s
ON s.submission_payload->>'request_id' = p.preflight_payload->>'request_id'
LEFT JOIN ${INTENT_REQUEST_OUTCOMES_TABLE} o
ON o.request_id = p.preflight_payload->>'request_id'
ORDER BY COALESCE(
o.outcome_observed_at,
s.submission_observed_at,
s.submission_ingested_at,
p.preflight_observed_at,
p.preflight_ingested_at
) DESC
LIMIT $1
`,
[Math.max(1, Number(limit) || 20)],
);
return result.rows.map(normalizeIntentRequestRow);
}
export async function loadLatestInventorySnapshot(pool) {
const latest = await loadLatestEventPayload(pool, 'intent_inventory_snapshots');
if (!latest) return null;
return {
ingested_at: latest.ingested_at,
payload: latest.payload,
};
}
export async function loadLatestMarketPrice(pool) {
const latest = await loadLatestEventPayload(pool, 'market_price_events');
if (!latest) return null;
return {
ingested_at: latest.ingested_at,
payload: latest.payload,
};
}
export async function loadRecentQuotes(pool, { limit = 10 } = {}) {
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM swap_demand_events
ORDER BY ingested_at DESC
LIMIT $1
`,
[limit],
);
return result.rows.map(normalizeRecentQuoteRow);
}
export async function loadSubmissionSummary(pool) {
const result = await pool.query(`
SELECT
COUNT(*)::INT AS total,
MAX(COALESCE(observed_at, ingested_at)) AS last_submission_at
FROM trade_execution_results
WHERE payload->>'status' = 'submitted'
`);
return {
total: Number(result.rows[0]?.total || 0),
last_submission_at: toIsoTimestamp(result.rows[0]?.last_submission_at),
};
}
export async function loadSubmissionPage(pool, { page = 1, pageSize = 20 } = {}) {
const normalizedPage = Math.max(1, Number(page) || 1);
const normalizedPageSize = Math.max(1, Number(pageSize) || 20);
const offset = (normalizedPage - 1) * normalizedPageSize;
const [countResult, rowsResult] = await Promise.all([
pool.query(`
SELECT COUNT(*)::INT AS total
FROM trade_execution_results
WHERE payload->>'status' = 'submitted'
`),
pool.query(
`
SELECT
r.observed_at AS result_observed_at,
r.ingested_at AS result_ingested_at,
r.payload AS result_payload,
c.payload AS command_payload,
d.payload AS decision_payload,
o.payload AS outcome_payload
FROM trade_execution_results r
LEFT JOIN execute_trade_commands c
ON c.decision_key = r.decision_key
LEFT JOIN trade_decisions d
ON d.decision_key = COALESCE(c.payload->>'decision_id', r.payload->>'decision_id')
LEFT JOIN ${QUOTE_OUTCOMES_TABLE} o
ON o.quote_id = r.quote_id
WHERE r.payload->>'status' = 'submitted'
ORDER BY COALESCE(r.observed_at, r.ingested_at) DESC
LIMIT $1
OFFSET $2
`,
[normalizedPageSize, offset],
),
]);
const total = Number(countResult.rows[0]?.total || 0);
return {
page: normalizedPage,
page_size: normalizedPageSize,
total,
total_pages: total > 0 ? Math.ceil(total / normalizedPageSize) : 1,
items: rowsResult.rows.map(normalizeSubmissionRow),
};
}
export async function loadRecentExecutionResults(pool, { limit = 20 } = {}) {
const result = await pool.query(
`
SELECT
r.observed_at AS result_observed_at,
r.ingested_at AS result_ingested_at,
r.payload AS result_payload,
c.ingested_at AS command_ingested_at,
c.payload AS command_payload,
d.payload AS decision_payload,
o.payload AS outcome_payload
FROM trade_execution_results r
LEFT JOIN execute_trade_commands c
ON c.decision_key = r.decision_key
LEFT JOIN trade_decisions d
ON d.decision_key = COALESCE(c.payload->>'decision_id', r.payload->>'decision_id')
LEFT JOIN ${QUOTE_OUTCOMES_TABLE} o
ON o.quote_id = r.quote_id
ORDER BY COALESCE(r.observed_at, r.ingested_at) DESC
LIMIT $1
`,
[limit],
);
return result.rows.map((row) => normalizeExecutionResultRow(row));
}
export async function loadRecentExecuteTradeCommands(pool, { limit = 20 } = {}) {
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM execute_trade_commands
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT $1
`,
[limit],
);
return result.rows.map((row) => normalizeExecuteTradeCommandRow(row));
}
export async function loadCurrentFundingObservations(pool) {
const result = await pool.query(`
SELECT DISTINCT ON (decision_key)
observed_at,
ingested_at,
payload
FROM funding_observations
WHERE decision_key IS NOT NULL
ORDER BY decision_key, ingested_at DESC
`);
return result.rows
.map((row) => ({
observed_at: toIsoTimestamp(row.observed_at),
ingested_at: toIsoTimestamp(row.ingested_at),
payload: row.payload,
}))
.sort((left, right) => (
Date.parse(
right.payload?.last_seen_at
|| right.observed_at
|| right.ingested_at
|| '',
) - Date.parse(
left.payload?.last_seen_at
|| left.observed_at
|| left.ingested_at
|| '',
)
));
}
export async function loadRecentDepositStatuses(pool, { limit = 20 } = {}) {
const normalizedLimit = Math.max(1, Number(limit) || 20);
const fetchLimit = Math.max(normalizedLimit * 50, 500);
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM liquidity_actions
WHERE payload->>'action_type' = 'deposit_status_observed'
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT $1
`,
[fetchLimit],
);
return normalizeDepositStatusRows(result.rows)
.sort((left, right) => (
timestampValue(right.observed_at || right.ingested_at)
- timestampValue(left.observed_at || left.ingested_at)
))
.slice(0, normalizedLimit);
}
export async function loadRecentAlertTransitions(pool, { limit = 20 } = {}) {
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM ops_alerts
ORDER BY ingested_at DESC
LIMIT $1
`,
[limit],
);
return result.rows.map((row) => ({
observed_at: toIsoTimestamp(row.observed_at),
ingested_at: toIsoTimestamp(row.ingested_at),
payload: row.payload,
}));
}
export async function loadRecentEnvironmentStatuses(pool, { limit = 20 } = {}) {
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM environment_status_events
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT $1
`,
[Math.max(1, Number(limit) || 20)],
);
return result.rows.map((row) => ({
observed_at: toIsoTimestamp(row.observed_at),
ingested_at: toIsoTimestamp(row.ingested_at),
payload: row.payload,
}));
}
export async function loadRecentTradeDecisions(pool, { limit = 20 } = {}) {
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM trade_decisions
ORDER BY COALESCE(observed_at, ingested_at) DESC
LIMIT $1
`,
[limit],
);
return result.rows.map((row) => ({
observed_at: toIsoTimestamp(row.observed_at),
ingested_at: toIsoTimestamp(row.ingested_at),
payload: row.payload,
}));
}
async function loadLatestEventPayload(pool, table, clause = 'ORDER BY ingested_at DESC LIMIT 1', params = []) {
const result = await pool.query(
`
SELECT ingested_at, payload
FROM ${table}
${clause}
`,
params,
);
if (!result.rows[0]) return null;
return {
ingested_at: result.rows[0].ingested_at ? new Date(result.rows[0].ingested_at).toISOString() : null,
payload: result.rows[0].payload,
};
}
async function loadNearestPricePayload(pool, anchorAt) {
const before = await loadLatestEventPayload(
pool,
'market_price_events',
'WHERE ingested_at <= $1 ORDER BY ingested_at DESC LIMIT 1',
[anchorAt],
);
if (before) return before;
return loadLatestEventPayload(
pool,
'market_price_events',
'WHERE ingested_at >= $1 ORDER BY ingested_at ASC LIMIT 1',
[anchorAt],
);
}
async function loadExternalAssetFlowsSince(pool, {
since,
btcAsset,
btcAssets = null,
eureAsset,
valuationAssets = [],
} = {}) {
const effectiveBtcAssets = normalizeBtcAssets({ btcAsset, btcAssets });
const [depositRows, withdrawalRows] = await Promise.all([
loadCreditedDepositRowsSince(pool, since),
loadCompletedWithdrawalRowsSince(pool, since),
]);
const flows = [];
for (const row of depositRows) {
flows.push(await normalizeExternalFlowRow(pool, {
row,
kind: 'deposit',
sign: 1n,
btcAsset: effectiveBtcAssets[0],
btcAssets: effectiveBtcAssets,
eureAsset,
valuationAssets,
}));
}
for (const row of withdrawalRows) {
flows.push(await normalizeExternalFlowRow(pool, {
row,
kind: 'withdrawal',
sign: -1n,
btcAsset: effectiveBtcAssets[0],
btcAssets: effectiveBtcAssets,
eureAsset,
valuationAssets,
}));
}
return flows
.filter(Boolean)
.sort((left, right) => timestampValue(left.effective_at) - timestampValue(right.effective_at));
}
async function loadCreditedDepositRowsSince(pool, since) {
const result = await pool.query(
`
SELECT observed_at, ingested_at, payload
FROM liquidity_actions
WHERE payload->>'action_type' = 'deposit_status_observed'
AND UPPER(payload->>'status') = ANY($1)
AND COALESCE(payload->'details'->>'tx_hash', '') <> ''
ORDER BY COALESCE(observed_at, ingested_at) DESC
`,
[CREDITED_LIQUIDITY_STATUSES],
);
return normalizeDepositStatusRows(result.rows)
.filter((row) => timestampValue(row.observed_at || row.ingested_at) > timestampValue(since));
}
async function loadCompletedWithdrawalRowsSince(pool, since) {
const result = await pool.query(
`
SELECT DISTINCT ON (
payload->'details'->>'withdrawal_hash',
payload->>'chain',
payload->>'asset_id'
)
observed_at,
ingested_at,
payload
FROM liquidity_actions
WHERE ingested_at > $1
AND payload->>'action_type' = 'withdrawal_status_changed'
AND UPPER(payload->>'status') = ANY($2)
AND COALESCE(payload->'details'->>'withdrawal_hash', '') <> ''
ORDER BY
payload->'details'->>'withdrawal_hash',
payload->>'chain',
payload->>'asset_id',
ingested_at DESC
`,
[since, COMPLETED_WITHDRAWAL_STATUSES],
);
return result.rows;
}
async function normalizeExternalFlowRow(pool, {
row,
kind,
sign,
btcAsset,
btcAssets = null,
eureAsset,
valuationAssets = [],
} = {}) {
const payload = row?.payload || {};
const details = payload.details || {};
const assetId = payload.asset_id || details.asset_id || null;
if (!assetId) return null;
const amount = String(details.amount || '0');
const effectiveAt = toIsoTimestamp(details.created_at || row.observed_at || row.ingested_at);
const signedUnits = (sign * BigInt(amount)).toString();
let referencePriceAtFlowTime = null;
let referencePriceEurePerUnitAtFlowTime = null;
const effectiveBtcAssets = normalizeBtcAssets({ btcAsset, btcAssets });
const flowBtcAsset = effectiveBtcAssets.find((asset) => asset.assetId === assetId);
const valuationAsset = valuationAssets.find((asset) => asset.assetId === assetId);
if (flowBtcAsset) {
const nearestPrice = await loadNearestPricePayload(pool, effectiveAt);
referencePriceAtFlowTime = nearestPrice?.payload?.eure_per_btc || null;
} else if (valuationAsset) {
referencePriceEurePerUnitAtFlowTime = valuationAsset.currentUnitValueEure || null;
} else if (assetId !== eureAsset?.assetId) {
return null;
}
return {
flow_id:
kind === 'deposit'
? `deposit:${details.tx_hash || effectiveAt || Math.random().toString(16).slice(2)}`
: `withdrawal:${details.withdrawal_hash || effectiveAt || Math.random().toString(16).slice(2)}`,
kind,
asset_id: assetId,
effective_at: effectiveAt,
signed_units: signedUnits,
tx_hash: details.tx_hash || null,
withdrawal_hash: details.withdrawal_hash || null,
reference_price_eure_per_btc_at_flow_time: referencePriceAtFlowTime,
reference_price_eure_per_unit_at_flow_time: referencePriceEurePerUnitAtFlowTime,
};
}
function normalizeBtcAssets({ btcAsset = null, btcAssets = null } = {}) {
const assets = btcAssets?.length ? btcAssets : [btcAsset];
return [...new Map(
assets
.filter((asset) => asset?.assetId)
.map((asset) => [asset.assetId, asset]),
).values()];
}
function normalizePortfolioMetricRow(row) {
return {
metric_id: row.metric_id,
computed_at: row.computed_at ? new Date(row.computed_at).toISOString() : null,
baseline_anchor_at: row.baseline_anchor_at ? new Date(row.baseline_anchor_at).toISOString() : null,
baseline_status: row.baseline_status,
payload: row.payload,
};
}
function normalizeQuoteOutcomeRow(row) {
const payload = row.payload || {};
return {
quote_id: row.quote_id || payload.quote_id || null,
decision_id: row.decision_id || payload.decision_id || null,
command_id: row.command_id || payload.command_id || null,
pair: payload.pair || null,
direction: payload.direction || null,
request_kind: payload.request_kind || null,
gross_edge_pct: payload.gross_edge_pct || null,
eure_notional: payload.eure_notional || null,
execution_result_status: row.execution_result_status || payload.execution_result_status || null,
execution_result_code: row.execution_result_code || payload.execution_result_code || null,
submitted_at: toIsoTimestamp(row.submitted_at || payload.submitted_at),
command_at: toIsoTimestamp(row.command_at || payload.command_at),
outcome_status: row.outcome_status || payload.outcome_status || null,
outcome_observed_at: toIsoTimestamp(row.outcome_observed_at || payload.outcome_observed_at),
outcome_source: row.outcome_source || payload.outcome_source || null,
outcome_reason: payload.outcome_reason || null,
attribution_status: row.attribution_status || payload.attribution_status || null,
attribution_method: row.attribution_method || payload.attribution_method || null,
attributed_inventory_delta:
row.attributed_inventory_delta
|| payload.attributed_inventory_delta
|| null,
computed_at: toIsoTimestamp(row.computed_at),
evidence: payload.evidence || null,
};
}
function normalizeEventPayloadRow(row) {
if (!row) return null;
return {
observed_at: toIsoTimestamp(row.observed_at),
ingested_at: toIsoTimestamp(row.ingested_at),
payload: row.payload || {},
};
}
function normalizeIntentRequestSubmissionPayload(payload = null) {
if (!payload) return null;
return {
request_id: payload.request_id || null,
idempotency_key: payload.idempotency_key || null,
submission_id: payload.submission_id || null,
status: payload.status || null,
result_code: payload.result_code || null,
result_text: payload.result_text || null,
quote_hash: payload.quote_hash || null,
intent_hash: payload.intent_hash || null,
destination_amount_units: payload.destination_amount_units || null,
nonce: payload.nonce || null,
submitted_at: toIsoTimestamp(payload.submitted_at),
relay_status: payload.relay_status || null,
relay_status_response: payload.relay_status_response || null,
status_checked_at: toIsoTimestamp(payload.status_checked_at),
};
}
export function normalizeIntentRequestRow(row) {
const preflight = row.preflight_payload || {};
const submission = row.submission_payload || null;
const outcome = row.outcome_payload || null;
const state = outcome?.outcome_status
|| mapSubmissionStatusToRequestState(submission?.status)
|| preflight.state
|| 'unknown';
const reasonCode = outcome?.outcome_reason
|| submission?.result_code
|| preflight.reason_code
|| 'reason_unknown';
const reasonText = outcome?.reason_text
|| (outcome?.outcome_reason ? humanizeIntentRequestReason(outcome.outcome_reason) : null)
|| submission?.result_text
|| preflight.reason_text
|| reasonCode.replaceAll('_', ' ');
return {
request_id: preflight.request_id || null,
idempotency_key: preflight.idempotency_key || null,
submission_id: submission?.submission_id || outcome?.submission_id || null,
intent_hash: submission?.intent_hash || outcome?.intent_hash || null,
quote_hash: submission?.quote_hash || preflight.selected_quote?.quote_hash || null,
created_at: toIsoTimestamp(preflight.created_at || row.preflight_observed_at || row.preflight_ingested_at),
submitted_at: toIsoTimestamp(submission?.submitted_at || outcome?.submitted_at || row.submission_observed_at || row.submission_ingested_at),
resolved_at: isTerminalIntentRequestState(state)
? toIsoTimestamp(outcome?.outcome_observed_at || row.outcome_observed_at || submission?.submitted_at)
: null,
state,
state_label: labelIntentRequestState(state),
reason_code: reasonCode,
reason_text: reasonText,
source_asset_id: preflight.source_asset_id || null,
source_symbol: preflight.source_symbol || null,
source_decimals: preflight.source_decimals ?? null,
destination_asset_id: preflight.destination_asset_id || null,
destination_symbol: preflight.destination_symbol || null,
destination_decimals: preflight.destination_decimals ?? null,
source_amount_units: preflight.source_amount_units || null,
expected_destination_amount_units: preflight.expected_destination_amount_units || null,
min_destination_amount_units: preflight.min_destination_amount_units || null,
quoted_destination_amount_units:
submission?.destination_amount_units
|| preflight.quoted_destination_amount_units
|| preflight.selected_quote?.amount_out
|| null,
slippage_bps: preflight.slippage_bps ?? null,
deadline_at: preflight.deadline_at || null,
signer_account_id: preflight.signer_account_id || null,
signer_public_key: preflight.signer_public_key || null,
verifier_contract: preflight.verifier_contract || null,
nonce: submission?.nonce || null,
nonce_policy: preflight.nonce_policy || null,
live_submit_capable: preflight.live_submit_capable === true && !submission,
solver_quote_count: preflight.solver_quote_count || 0,
selected_quote: preflight.selected_quote || null,
submission_status: submission?.status || outcome?.submission_status || null,
relay_status: submission?.relay_status || outcome?.evidence?.relay_status || null,
relay_response: submission?.relay_response || null,
relay_status_response: submission?.relay_status_response || null,
outcome_status: outcome?.outcome_status || null,
outcome_source: outcome?.outcome_source || null,
attribution_status: outcome?.attribution_status || null,
attribution_method: outcome?.attribution_method || null,
attributed_inventory_delta: outcome?.attributed_inventory_delta || null,
has_settlement_evidence: Boolean(
outcome?.attributed_inventory_delta
&& ['heuristic_match', 'linked_settlement'].includes(outcome?.attribution_status),
),
lifecycle: {
preflight,
submission,
outcome,
},
};
}
function humanizeIntentRequestReason(reason) {
const normalized = String(reason || '').trim();
const labels = {
accepted_by_relay_without_settlement:
'Relay accepted the signed request; waiting for durable EURe decrease and BTC increase evidence.',
relay_settled_but_inventory_delta_missing:
'Relay reported settlement, but no matching durable inventory movement is linked yet.',
deadline_elapsed_without_settlement:
'Deadline and grace window elapsed without matching EURe decrease and BTC increase evidence.',
matched_inventory_delta:
'Matched durable EURe decrease and BTC increase evidence.',
ambiguous_inventory_delta_match:
'More than one inventory movement could match this request; no completion is assigned.',
relay_not_found_or_not_valid:
'Relay reported the intent as not found or not valid.',
relay_settled_without_expected_inventory_delta:
'Relay reports settlement, but durable inventory does not show the expected EURe decrease and BTC increase.',
solver_quote_unanswered:
'The relay returned no solver quotes for this request.',
};
return labels[normalized] || normalized.replaceAll('_', ' ');
}
function mapSubmissionStatusToRequestState(status) {
if (status === 'accepted_by_relay') return 'awaiting_settlement';
if (status === 'submit_requested') return 'submitted';
if (status === 'blocked') return 'blocked';
if (status === 'failed') return 'failed';
return null;
}
function labelIntentRequestState(state) {
const labels = {
draft: 'Draft',
blocked: 'Blocked',
submitted: 'Submitted',
accepted_by_relay: 'Accepted by relay',
awaiting_settlement: 'Awaiting settlement',
failed: 'Failed',
not_filled: 'Not filled',
completed: 'Completed',
};
return labels[state] || state || 'Unknown';
}
function isTerminalIntentRequestState(state) {
return ['blocked', 'failed', 'not_filled', 'completed'].includes(state);
}
function normalizeRecentQuoteRow(row) {
const payload = row.payload || {};
return {
quote_id: payload.quote_id || null,
pair: payload.pair || buildPair(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,
min_deadline_ms: payload.min_deadline_ms ?? null,
observed_at: toIsoTimestamp(row.observed_at),
ingested_at: toIsoTimestamp(row.ingested_at),
};
}
function normalizeSubmissionRow(row) {
const resultPayload = row.result_payload || {};
const commandPayload = row.command_payload || {};
const decisionPayload = row.decision_payload || {};
const outcomePayload = row.outcome_payload || {};
return {
command_id: resultPayload.command_id || commandPayload.command_id || null,
decision_id:
commandPayload.decision_id
|| resultPayload.decision_id
|| decisionPayload.decision_id
|| null,
execution_key: resultPayload.execution_key || commandPayload.execution_key || null,
quote_id: resultPayload.quote_id || commandPayload.quote_id || decisionPayload.quote_id || null,
pair: resultPayload.pair || commandPayload.pair || decisionPayload.pair || null,
pair_id: commandPayload.pair_id || decisionPayload.pair_id || resultPayload.pair_id || null,
pair_config_id:
commandPayload.pair_config_id
|| decisionPayload.pair_config_id
|| resultPayload.pair_config_id
|| null,
pair_config_version:
commandPayload.pair_config_version
|| decisionPayload.pair_config_version
|| resultPayload.pair_config_version
|| null,
edge_bps: commandPayload.edge_bps || decisionPayload.edge_bps || resultPayload.edge_bps || null,
observed_at: toIsoTimestamp(row.result_observed_at || row.result_ingested_at),
ingested_at: toIsoTimestamp(row.result_ingested_at),
status: resultPayload.status || null,
result_code: resultPayload.result_code || null,
outcome_status: outcomePayload.outcome_status || null,
outcome_reason: outcomePayload.outcome_reason || null,
attribution_status: outcomePayload.attribution_status || null,
attributed_inventory_delta: outcomePayload.attributed_inventory_delta || null,
request_kind: commandPayload.request_kind || decisionPayload.request_kind || null,
asset_in: commandPayload.asset_in || null,
asset_out: commandPayload.asset_out || null,
amount_in: resolveTradeAmount(commandPayload, 'amount_in'),
amount_out: resolveTradeAmount(commandPayload, 'amount_out'),
quoted_amount_in: commandPayload.amount_in || null,
quoted_amount_out: commandPayload.amount_out || null,
gross_edge_pct: decisionPayload.gross_edge_pct || null,
decision_reason: decisionPayload.decision_reason || null,
direction: decisionPayload.direction || null,
};
}
function normalizeExecuteTradeCommandRow(row) {
const payload = row.payload || {};
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,
pair_id: payload.pair_id || null,
pair_config_id: payload.pair_config_id || null,
pair_config_version: payload.pair_config_version || null,
edge_bps: payload.edge_bps || null,
direction: payload.direction || null,
request_kind: payload.request_kind || null,
asset_in: payload.asset_in || null,
asset_out: payload.asset_out || null,
amount_in: resolveTradeAmount(payload, 'amount_in'),
amount_out: resolveTradeAmount(payload, 'amount_out'),
observed_at: toIsoTimestamp(row.observed_at || row.ingested_at),
ingested_at: toIsoTimestamp(row.ingested_at),
};
}
function normalizeExecutionResultRow(row) {
const resultPayload = row.result_payload || {};
const commandPayload = row.command_payload || {};
const decisionPayload = row.decision_payload || {};
const outcomePayload = row.outcome_payload || {};
return {
command_id: resultPayload.command_id || commandPayload.command_id || null,
decision_id:
commandPayload.decision_id
|| resultPayload.decision_id
|| decisionPayload.decision_id
|| null,
execution_key: resultPayload.execution_key || commandPayload.execution_key || null,
quote_id: resultPayload.quote_id || commandPayload.quote_id || decisionPayload.quote_id || null,
pair: resultPayload.pair || commandPayload.pair || decisionPayload.pair || null,
pair_id: commandPayload.pair_id || decisionPayload.pair_id || resultPayload.pair_id || null,
pair_config_id:
commandPayload.pair_config_id
|| decisionPayload.pair_config_id
|| resultPayload.pair_config_id
|| null,
pair_config_version:
commandPayload.pair_config_version
|| decisionPayload.pair_config_version
|| resultPayload.pair_config_version
|| null,
edge_bps: commandPayload.edge_bps || decisionPayload.edge_bps || resultPayload.edge_bps || null,
command_at: toIsoTimestamp(row.command_ingested_at),
result_at: toIsoTimestamp(row.result_observed_at || row.result_ingested_at),
status: resultPayload.status || null,
result_code: resultPayload.result_code || null,
outcome_status:
outcomePayload.outcome_status
|| resultPayload.outcome_status
|| resultPayload.venue_outcome_status
|| resultPayload.trade_outcome_status
|| null,
outcome_reason:
outcomePayload.outcome_reason
|| resultPayload.outcome_reason
|| resultPayload.venue_outcome_reason
|| resultPayload.trade_outcome_reason
|| null,
outcome_source: outcomePayload.outcome_source || null,
attribution_status: outcomePayload.attribution_status || null,
attribution_method: outcomePayload.attribution_method || null,
attributed_inventory_delta: outcomePayload.attributed_inventory_delta || null,
outcome_payload: outcomePayload.quote_id ? outcomePayload : null,
venue_response: resultPayload.venue_response || null,
error_message: resultPayload.error?.message || null,
note: resultPayload.note || null,
};
}
function resolveTradeAmount(commandPayload, field) {
const quoteOutputField = commandPayload?.quote_output?.[field];
const proposedField = commandPayload?.[`proposed_${field}`];
return quoteOutputField || proposedField || commandPayload?.[field] || null;
}
function buildPair(assetIn, assetOut) {
if (!assetIn || !assetOut) return null;
return `${assetIn}->${assetOut}`;
}
function toIsoTimestamp(value) {
if (!value) return null;
const date = new Date(value);
return Number.isNaN(date.getTime()) ? null : date.toISOString();
}
function timestampValue(value) {
const parsed = Date.parse(value || '');
return Number.isFinite(parsed) ? parsed : -Infinity;
}
function buildDepositStatusRowKey(payload) {
const details = payload?.details || {};
return [
details.tx_hash || 'no-tx',
payload?.chain || details.chain || 'no-chain',
payload?.asset_id || details.asset_id || 'no-asset',
details.address || 'no-address',
details.amount || 'no-amount',
].join('|');
}
function normalizeDepositStatusRows(rows = []) {
const byKey = new Map();
for (const row of rows) {
const key = buildDepositStatusRowKey(row.payload);
const effectiveAt = depositStatusEffectiveAt(row);
const latestSortAt = timestampValue(row.observed_at || row.ingested_at);
const existing = byKey.get(key);
if (!existing) {
byKey.set(key, {
latest: row,
latestSortAt,
firstEffectiveAt: effectiveAt,
});
continue;
}
if (latestSortAt > existing.latestSortAt) {
existing.latest = row;
existing.latestSortAt = latestSortAt;
}
const candidateEffectiveTs = timestampValue(effectiveAt);
const existingEffectiveTs = timestampValue(existing.firstEffectiveAt);
if (
Number.isFinite(candidateEffectiveTs)
&& (!Number.isFinite(existingEffectiveTs) || candidateEffectiveTs < existingEffectiveTs)
) {
existing.firstEffectiveAt = effectiveAt;
}
}
return [...byKey.values()].map(({ latest, firstEffectiveAt }) => {
const effectiveAt = firstEffectiveAt || toIsoTimestamp(latest.observed_at || latest.ingested_at);
return {
observed_at: effectiveAt,
ingested_at: toIsoTimestamp(latest.ingested_at),
payload: withDepositCreatedAt(latest.payload, effectiveAt),
};
});
}
function depositStatusEffectiveAt(row) {
return toIsoTimestamp(
row?.payload?.details?.created_at
|| row?.observed_at
|| row?.ingested_at,
);
}
function withDepositCreatedAt(payload, effectiveAt) {
if (!effectiveAt) return payload;
const details = payload?.details || {};
return {
...payload,
details: {
...details,
created_at: details.created_at || effectiveAt,
},
};
}
async function ensureExpressionIndex(pool, { name, table, expression }) {
await pool.query(`
CREATE INDEX IF NOT EXISTS ${name}
ON ${table} (${expression})
`);
}