unrip/src/lib/config.mjs
philipp 2ffa4b17f1
Some checks failed
deploy / deploy (push) Failing after 34s
Move trading config into Postgres
Proof: npm test passed 159/159; npm run operator-dashboard:build passed; repo-local Postgres importer smoke test imported 163 live 1Click tokens with only 3 inventory-enabled seed assets and nBTC/EURe pairs at 49 bps.

Assumptions: Forgejo main push is the repo deployment path; production has existing repo-managed POSTGRES_URL/POSTGRES_PASSWORD/NEAR_INTENTS_API_KEY secrets; startup seed may create initial current nBTC/EURe config but must preserve DB runtime pair flags after creation.

Still fake: no live funds movement was attempted; imported supported assets remain catalog-only unless explicitly enabled in DB; production rollout evidence still depends on the Forgejo deploy job completing after this push.
2026-05-12 21:34:58 +02:00

631 lines
25 KiB
JavaScript

import { loadDotenv } from './env.mjs';
const DEFAULTS = {
nearIntentsWsUrl: 'wss://solver-relay-v2.chaindefuser.com/ws',
nearIntentsRpcUrl: 'https://solver-relay-v2.chaindefuser.com/rpc',
nearBridgeRpcUrl: 'https://bridge.chaindefuser.com/rpc',
nearRpcUrl: 'https://near.lava.build',
nearVerifierContract: 'intents.near',
nearIntentsControlApiEnabled: true,
nearIntentsControlHost: '0.0.0.0',
nearIntentsControlPort: 8081,
marketReferenceControlPort: 8082,
inventorySyncControlPort: 8083,
liquidityManagerControlPort: 8084,
historyWriterControlPort: 8085,
strategyEngineControlPort: 8086,
tradeExecutorControlPort: 8087,
opsSentinelControlPort: 8088,
operatorDashboardControlPort: 8090,
kafkaBrokers: ['127.0.0.1:9092'],
kafkaClientId: 'unrip',
kafkaTopicRawNearIntentsQuote: 'raw.near_intents.quote',
kafkaTopicNormSwapDemand: 'norm.swap_demand',
kafkaTopicRefMarketPrice: 'ref.market_price',
kafkaTopicStateIntentInventory: 'state.intent_inventory',
kafkaTopicOpsLiquidityAction: 'ops.liquidity_action',
kafkaTopicOpsFundingObservation: 'ops.funding_observation',
kafkaTopicOpsAlert: 'ops.alert',
kafkaTopicOpsEnvironmentStatus: 'ops.environment_status',
kafkaTopicDecisionTradeDecision: 'decision.trade_decision',
kafkaTopicCmdExecuteTrade: 'cmd.execute_trade',
kafkaTopicExecTradeResult: 'exec.trade_result',
kafkaConsumerGroupHistory: 'history-writer-v1',
kafkaConsumerGroupInventory: 'inventory-sync-v1',
kafkaConsumerGroupStrategy: 'strategy-engine-v1',
kafkaConsumerGroupExecutor: 'trade-executor-v1',
kafkaConsumerGroupOpsSentinel: 'ops-sentinel-v1',
kafkaConsumerGroupOperatorDashboard: 'operator-dashboard-v1',
historyWriterDerivedRefreshMaxEventAgeMs: 30_000,
strategyStateDir: './var/strategy-state',
executorStateDir: './var/executor-state',
liquidityStateDir: './var/liquidity-state',
postgresUrl: 'postgresql://unrip:unrip@127.0.0.1:5432/unrip',
projectName: 'unrip',
projectNamespace: 'unrip',
tradingBtcAssetId: 'nep141:nbtc.bridge.near',
tradingBtcTrackedAssetIds: [
'nep141:nbtc.bridge.near',
'nep141:btc.omft.near',
],
tradingBtcSymbol: 'BTC',
tradingBtcLabel: 'BTC / nBTC reserve',
tradingBtcLegacyLabel: 'BTC / legacy OMFT',
tradingBtcDecimals: 8,
tradingBtcChain: 'btc:mainnet',
tradingBtcWithdrawAddress: '',
tradingEureAssetId: 'nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near',
tradingEureSymbol: 'EURe',
tradingEureDecimals: 18,
tradingEureChain: 'eth:100',
tradingEureWithdrawAddress: '',
marketReferenceRefreshMs: 5_000,
marketReferenceCoinGeckoRefreshMs: 15_000,
marketReferenceMaxAgeMs: 30_000,
marketReferenceKrakenTickerUrl: 'https://api.kraken.com/0/public/Ticker?pair=XBTEUR',
marketReferenceCoinGeckoUrl:
'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=eur',
inventorySyncRefreshMs: 15_000,
liquidityRefreshMs: 30_000,
strategyGrossThresholdPct: 0.49,
strategyInitialArmed: false,
strategyMaxNotionalEure: 5,
strategyPriceMaxAgeMs: 30_000,
strategyInventoryMaxAgeMs: 30_000,
executorInitialArmed: false,
executorResponseTimeoutMs: 10_000,
intentRequestDefaultAmountEure: 5,
intentRequestMaxAmountEure: 5,
intentRequestDefaultSlippageBps: 200,
intentRequestMaxSlippageBps: 200,
intentRequestMinDeadlineMs: 60_000,
intentRequestQuoteTimeoutMs: 10_000,
intentRequestPublishTimeoutMs: 10_000,
intentRequestStatusTimeoutMs: 10_000,
intentRequestInventoryMaxAgeMs: 30_000,
intentRequestPriceMaxAgeMs: 30_000,
withdrawalsFrozen: true,
btcFundingObserverEnabled: true,
btcFundingObserverBaseUrl: 'https://mempool.space/api',
fundingObservationStuckMs: 60 * 60 * 1000,
opsSentinelEvaluationMs: 5_000,
opsSentinelFundingCreditPendingMs: 5 * 60 * 1000,
opsSentinelIngestMessageStaleMs: 30_000,
opsSentinelIngestQuoteStaleMs: 30_000,
opsSentinelIngestPublishStaleMs: 30_000,
opsSentinelExecutorRelayStaleMs: 30_000,
opsSentinelHistoryWriterStaleMs: 45_000,
opsSentinelDashboardSourceDegradedMs: 30_000,
opsSentinelSelfStaleMs: 20_000,
opsSentinelAnomalyWindowSize: 6,
opsSentinelAnomalyQuoteRateCollapseRatio: 0.25,
opsSentinelAnomalyReconnectSpikeMultiplier: 2,
opsSentinelContainmentCooldownMs: 60_000,
opsSentinelAlertWebhookUrl: '',
opsSentinelAlertWebhookTimeoutMs: 5_000,
operatorDashboardAuthMode: 'stub',
operatorDashboardAuthUsername: 'admin',
operatorDashboardAuthPassword: '',
operatorDashboardAuthRealm: 'unrip operator dashboard',
operatorDashboardQuoteLimit: 10,
operatorDashboardTradePageSize: 20,
operatorDashboardUpstreamTimeoutMs: 3_000,
nearIntentsStatusServicesUrl: 'https://status.near-intents.org/api/services',
nearIntentsStatusPostsUrl: 'https://status.near-intents.org/api/posts?is_featured=true&limit=500',
nearIntentsStatusPostEnumsUrl: 'https://status.near-intents.org/api/post_enums',
nearIntentsStatusTimeoutMs: 3_000,
nearIntentsStatusPollMs: 60_000,
notificationNtfyBaseUrl: '',
notificationNtfyTopic: 'unrip',
notificationNtfyToken: '',
notificationNtfyTimeoutMs: 5_000,
};
function splitCsv(value) {
return String(value || '')
.split(',')
.map((part) => part.trim())
.filter(Boolean);
}
function parseNumber(value, fallback) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : fallback;
}
function parseBoolean(value, fallback) {
if (value == null || value === '') return fallback;
const normalized = String(value).trim().toLowerCase();
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
return fallback;
}
function unique(values) {
return [...new Set(values.filter(Boolean))];
}
function buildAsset({
assetId,
symbol,
decimals,
chain,
withdrawAddress = '',
label = symbol,
role = 'tracked',
}) {
return {
assetId,
symbol,
label,
decimals,
chain,
withdrawAddress,
role,
};
}
function buildBtcAssetLabel(assetId, tradingAssetId) {
if (assetId === tradingAssetId) return DEFAULTS.tradingBtcLabel;
if (assetId === 'nep141:btc.omft.near') return DEFAULTS.tradingBtcLegacyLabel;
return `${DEFAULTS.tradingBtcSymbol} / ${assetId.replace(/^nep141:/, '')}`;
}
function defaultControlBaseUrl({ serviceName, port, namespace }) {
if (process.env.KUBERNETES_SERVICE_HOST) {
return `http://${serviceName}.${namespace}.svc.cluster.local:${port}`;
}
return `http://127.0.0.1:${port}`;
}
export function loadConfig({ envPath = '.env' } = {}) {
loadDotenv(envPath);
const tradingBtc = buildAsset({
assetId: DEFAULTS.tradingBtcAssetId,
symbol: DEFAULTS.tradingBtcSymbol,
label: DEFAULTS.tradingBtcLabel,
decimals: DEFAULTS.tradingBtcDecimals,
chain: DEFAULTS.tradingBtcChain,
withdrawAddress: DEFAULTS.tradingBtcWithdrawAddress,
role: 'trading',
});
const trackedBtcAssetIds = unique([
tradingBtc.assetId,
...DEFAULTS.tradingBtcTrackedAssetIds,
]);
const tradingBtcAssets = trackedBtcAssetIds.map((assetId) => {
if (assetId === tradingBtc.assetId) return tradingBtc;
return buildAsset({
assetId,
symbol: tradingBtc.symbol,
label: buildBtcAssetLabel(assetId, tradingBtc.assetId),
decimals: tradingBtc.decimals,
chain: tradingBtc.chain,
withdrawAddress: tradingBtc.withdrawAddress,
role: 'legacy',
});
});
const tradingEure = buildAsset({
assetId: DEFAULTS.tradingEureAssetId,
symbol: DEFAULTS.tradingEureSymbol,
label: DEFAULTS.tradingEureSymbol,
decimals: DEFAULTS.tradingEureDecimals,
chain: DEFAULTS.tradingEureChain,
withdrawAddress: DEFAULTS.tradingEureWithdrawAddress,
role: 'trading',
});
const trackedAssets = [
...tradingBtcAssets,
tradingEure,
];
const projectName = process.env.PROJECT_NAME || DEFAULTS.projectName;
const projectNamespace =
process.env.PROJECT_NAMESPACE || projectName || DEFAULTS.projectNamespace;
return {
nearIntentsApiKey: process.env.NEAR_INTENTS_API_KEY || '',
nearIntentsAccountId: process.env.NEAR_INTENTS_ACCOUNT_ID || '',
nearIntentsSignerPrivateKey: process.env.NEAR_INTENTS_SIGNER_PRIVATE_KEY || '',
nearIntentsWsUrl: process.env.NEAR_INTENTS_WS_URL || DEFAULTS.nearIntentsWsUrl,
nearIntentsRpcUrl: process.env.NEAR_INTENTS_RPC_URL || DEFAULTS.nearIntentsRpcUrl,
nearBridgeRpcUrl: process.env.NEAR_INTENTS_BRIDGE_RPC_URL || DEFAULTS.nearBridgeRpcUrl,
nearRpcUrl: process.env.NEAR_RPC_URL || DEFAULTS.nearRpcUrl,
nearVerifierContract:
process.env.NEAR_INTENTS_VERIFIER_CONTRACT || DEFAULTS.nearVerifierContract,
nearIntentsControlApiEnabled: parseBoolean(
process.env.NEAR_INTENTS_CONTROL_API_ENABLED,
DEFAULTS.nearIntentsControlApiEnabled,
),
nearIntentsControlHost:
process.env.NEAR_INTENTS_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
nearIntentsControlPort: parseNumber(
process.env.NEAR_INTENTS_CONTROL_PORT,
DEFAULTS.nearIntentsControlPort,
),
nearIntentsControlBaseUrl:
process.env.NEAR_INTENTS_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'near-intents-ingest',
port: parseNumber(
process.env.NEAR_INTENTS_CONTROL_PORT,
DEFAULTS.nearIntentsControlPort,
),
namespace: projectNamespace,
}),
marketReferenceControlHost:
process.env.MARKET_REFERENCE_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
marketReferenceControlPort: parseNumber(
process.env.MARKET_REFERENCE_CONTROL_PORT,
DEFAULTS.marketReferenceControlPort,
),
marketReferenceControlBaseUrl:
process.env.MARKET_REFERENCE_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'market-reference-ingest',
port: parseNumber(
process.env.MARKET_REFERENCE_CONTROL_PORT,
DEFAULTS.marketReferenceControlPort,
),
namespace: projectNamespace,
}),
inventorySyncControlHost:
process.env.INVENTORY_SYNC_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
inventorySyncControlPort: parseNumber(
process.env.INVENTORY_SYNC_CONTROL_PORT,
DEFAULTS.inventorySyncControlPort,
),
inventorySyncControlBaseUrl:
process.env.INVENTORY_SYNC_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'inventory-sync',
port: parseNumber(
process.env.INVENTORY_SYNC_CONTROL_PORT,
DEFAULTS.inventorySyncControlPort,
),
namespace: projectNamespace,
}),
liquidityManagerControlHost:
process.env.LIQUIDITY_MANAGER_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
liquidityManagerControlPort: parseNumber(
process.env.LIQUIDITY_MANAGER_CONTROL_PORT,
DEFAULTS.liquidityManagerControlPort,
),
liquidityManagerControlBaseUrl:
process.env.LIQUIDITY_MANAGER_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'liquidity-manager',
port: parseNumber(
process.env.LIQUIDITY_MANAGER_CONTROL_PORT,
DEFAULTS.liquidityManagerControlPort,
),
namespace: projectNamespace,
}),
historyWriterControlHost:
process.env.HISTORY_WRITER_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
historyWriterControlPort: parseNumber(
process.env.HISTORY_WRITER_CONTROL_PORT,
DEFAULTS.historyWriterControlPort,
),
historyWriterControlBaseUrl:
process.env.HISTORY_WRITER_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'history-writer',
port: parseNumber(
process.env.HISTORY_WRITER_CONTROL_PORT,
DEFAULTS.historyWriterControlPort,
),
namespace: projectNamespace,
}),
opsSentinelControlHost:
process.env.OPS_SENTINEL_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
opsSentinelControlPort: parseNumber(
process.env.OPS_SENTINEL_CONTROL_PORT,
DEFAULTS.opsSentinelControlPort,
),
opsSentinelControlBaseUrl:
process.env.OPS_SENTINEL_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'ops-sentinel',
port: parseNumber(
process.env.OPS_SENTINEL_CONTROL_PORT,
DEFAULTS.opsSentinelControlPort,
),
namespace: projectNamespace,
}),
strategyEngineControlHost:
process.env.STRATEGY_ENGINE_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
strategyEngineControlPort: parseNumber(
process.env.STRATEGY_ENGINE_CONTROL_PORT,
DEFAULTS.strategyEngineControlPort,
),
strategyEngineControlBaseUrl:
process.env.STRATEGY_ENGINE_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'strategy-engine',
port: parseNumber(
process.env.STRATEGY_ENGINE_CONTROL_PORT,
DEFAULTS.strategyEngineControlPort,
),
namespace: projectNamespace,
}),
tradeExecutorControlHost:
process.env.TRADE_EXECUTOR_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
tradeExecutorControlPort: parseNumber(
process.env.TRADE_EXECUTOR_CONTROL_PORT,
DEFAULTS.tradeExecutorControlPort,
),
tradeExecutorControlBaseUrl:
process.env.TRADE_EXECUTOR_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'trade-executor',
port: parseNumber(
process.env.TRADE_EXECUTOR_CONTROL_PORT,
DEFAULTS.tradeExecutorControlPort,
),
namespace: projectNamespace,
}),
operatorDashboardControlHost:
process.env.OPERATOR_DASHBOARD_CONTROL_HOST || DEFAULTS.nearIntentsControlHost,
operatorDashboardControlPort: parseNumber(
process.env.OPERATOR_DASHBOARD_CONTROL_PORT,
DEFAULTS.operatorDashboardControlPort,
),
operatorDashboardControlBaseUrl:
process.env.OPERATOR_DASHBOARD_CONTROL_BASE_URL
|| defaultControlBaseUrl({
serviceName: 'operator-dashboard',
port: parseNumber(
process.env.OPERATOR_DASHBOARD_CONTROL_PORT,
DEFAULTS.operatorDashboardControlPort,
),
namespace: projectNamespace,
}),
kafkaBrokers: splitCsv(process.env.KAFKA_BROKERS).length
? splitCsv(process.env.KAFKA_BROKERS)
: DEFAULTS.kafkaBrokers,
kafkaClientId: process.env.KAFKA_CLIENT_ID || DEFAULTS.kafkaClientId,
kafkaTopicRawNearIntentsQuote:
process.env.KAFKA_TOPIC_RAW_NEAR_INTENTS_QUOTE || DEFAULTS.kafkaTopicRawNearIntentsQuote,
kafkaTopicNormSwapDemand:
process.env.KAFKA_TOPIC_NORM_SWAP_DEMAND || DEFAULTS.kafkaTopicNormSwapDemand,
kafkaTopicRefMarketPrice:
process.env.KAFKA_TOPIC_REF_MARKET_PRICE || DEFAULTS.kafkaTopicRefMarketPrice,
kafkaTopicStateIntentInventory:
process.env.KAFKA_TOPIC_STATE_INTENT_INVENTORY || DEFAULTS.kafkaTopicStateIntentInventory,
kafkaTopicOpsLiquidityAction:
process.env.KAFKA_TOPIC_OPS_LIQUIDITY_ACTION || DEFAULTS.kafkaTopicOpsLiquidityAction,
kafkaTopicOpsFundingObservation:
process.env.KAFKA_TOPIC_OPS_FUNDING_OBSERVATION || DEFAULTS.kafkaTopicOpsFundingObservation,
kafkaTopicOpsAlert:
process.env.KAFKA_TOPIC_OPS_ALERT || DEFAULTS.kafkaTopicOpsAlert,
kafkaTopicOpsEnvironmentStatus:
process.env.KAFKA_TOPIC_OPS_ENVIRONMENT_STATUS || DEFAULTS.kafkaTopicOpsEnvironmentStatus,
kafkaTopicDecisionTradeDecision:
process.env.KAFKA_TOPIC_DECISION_TRADE_DECISION || DEFAULTS.kafkaTopicDecisionTradeDecision,
kafkaTopicCmdExecuteTrade:
process.env.KAFKA_TOPIC_CMD_EXECUTE_TRADE || DEFAULTS.kafkaTopicCmdExecuteTrade,
kafkaTopicExecTradeResult:
process.env.KAFKA_TOPIC_EXEC_TRADE_RESULT || DEFAULTS.kafkaTopicExecTradeResult,
kafkaConsumerGroupHistory:
process.env.KAFKA_CONSUMER_GROUP_HISTORY || DEFAULTS.kafkaConsumerGroupHistory,
kafkaConsumerGroupInventory:
process.env.KAFKA_CONSUMER_GROUP_INVENTORY || DEFAULTS.kafkaConsumerGroupInventory,
kafkaConsumerGroupStrategy:
process.env.KAFKA_CONSUMER_GROUP_STRATEGY || DEFAULTS.kafkaConsumerGroupStrategy,
kafkaConsumerGroupExecutor:
process.env.KAFKA_CONSUMER_GROUP_EXECUTOR || DEFAULTS.kafkaConsumerGroupExecutor,
kafkaConsumerGroupOpsSentinel:
process.env.KAFKA_CONSUMER_GROUP_OPS_SENTINEL || DEFAULTS.kafkaConsumerGroupOpsSentinel,
kafkaConsumerGroupOperatorDashboard:
process.env.KAFKA_CONSUMER_GROUP_OPERATOR_DASHBOARD
|| DEFAULTS.kafkaConsumerGroupOperatorDashboard,
historyWriterDerivedRefreshMaxEventAgeMs: parseNumber(
process.env.HISTORY_WRITER_DERIVED_REFRESH_MAX_EVENT_AGE_MS,
DEFAULTS.historyWriterDerivedRefreshMaxEventAgeMs,
),
strategyStateDir: process.env.STRATEGY_STATE_DIR || DEFAULTS.strategyStateDir,
executorStateDir: process.env.EXECUTOR_STATE_DIR || DEFAULTS.executorStateDir,
liquidityStateDir: process.env.LIQUIDITY_STATE_DIR || DEFAULTS.liquidityStateDir,
postgresUrl: process.env.POSTGRES_URL || DEFAULTS.postgresUrl,
projectName,
projectNamespace,
tradingBtc,
tradingBtcAssets,
tradingEure,
activePair: `${tradingBtc.assetId}->${tradingEure.assetId}`,
activeAssetIds: [tradingBtc.assetId, tradingEure.assetId],
trackedAssets,
trackedAssetIds: trackedAssets.map((asset) => asset.assetId),
assetRegistry: new Map(trackedAssets.map((asset) => [asset.assetId, asset])),
marketReferenceRefreshMs: parseNumber(
process.env.MARKET_REFERENCE_REFRESH_MS,
DEFAULTS.marketReferenceRefreshMs,
),
marketReferenceCoinGeckoRefreshMs: parseNumber(
process.env.MARKET_REFERENCE_COINGECKO_REFRESH_MS,
DEFAULTS.marketReferenceCoinGeckoRefreshMs,
),
marketReferenceMaxAgeMs: parseNumber(
process.env.MARKET_REFERENCE_MAX_AGE_MS,
DEFAULTS.marketReferenceMaxAgeMs,
),
marketReferenceKrakenTickerUrl:
process.env.MARKET_REFERENCE_KRAKEN_TICKER_URL || DEFAULTS.marketReferenceKrakenTickerUrl,
marketReferenceCoinGeckoUrl:
process.env.MARKET_REFERENCE_COINGECKO_URL || DEFAULTS.marketReferenceCoinGeckoUrl,
inventorySyncRefreshMs: parseNumber(
process.env.INVENTORY_SYNC_REFRESH_MS,
DEFAULTS.inventorySyncRefreshMs,
),
liquidityRefreshMs: parseNumber(
process.env.LIQUIDITY_REFRESH_MS,
DEFAULTS.liquidityRefreshMs,
),
strategyGrossThresholdPct: DEFAULTS.strategyGrossThresholdPct,
strategyInitialArmed: parseBoolean(
process.env.STRATEGY_INITIAL_ARMED,
DEFAULTS.strategyInitialArmed,
),
strategyMaxNotionalEure: DEFAULTS.strategyMaxNotionalEure,
strategyPriceMaxAgeMs: DEFAULTS.strategyPriceMaxAgeMs,
strategyInventoryMaxAgeMs: DEFAULTS.strategyInventoryMaxAgeMs,
executorInitialArmed: parseBoolean(
process.env.EXECUTOR_INITIAL_ARMED,
DEFAULTS.executorInitialArmed,
),
executorResponseTimeoutMs: parseNumber(
process.env.EXECUTOR_RESPONSE_TIMEOUT_MS,
DEFAULTS.executorResponseTimeoutMs,
),
intentRequestDefaultAmountEure: DEFAULTS.intentRequestDefaultAmountEure,
intentRequestMaxAmountEure: DEFAULTS.intentRequestMaxAmountEure,
intentRequestDefaultSlippageBps: DEFAULTS.intentRequestDefaultSlippageBps,
intentRequestMaxSlippageBps: DEFAULTS.intentRequestMaxSlippageBps,
intentRequestMinDeadlineMs: DEFAULTS.intentRequestMinDeadlineMs,
intentRequestQuoteTimeoutMs: parseNumber(
process.env.INTENT_REQUEST_QUOTE_TIMEOUT_MS,
DEFAULTS.intentRequestQuoteTimeoutMs,
),
intentRequestPublishTimeoutMs: parseNumber(
process.env.INTENT_REQUEST_PUBLISH_TIMEOUT_MS,
DEFAULTS.intentRequestPublishTimeoutMs,
),
intentRequestStatusTimeoutMs: parseNumber(
process.env.INTENT_REQUEST_STATUS_TIMEOUT_MS,
DEFAULTS.intentRequestStatusTimeoutMs,
),
intentRequestInventoryMaxAgeMs: DEFAULTS.intentRequestInventoryMaxAgeMs,
intentRequestPriceMaxAgeMs: DEFAULTS.intentRequestPriceMaxAgeMs,
withdrawalsFrozen: parseBoolean(
process.env.LIQUIDITY_WITHDRAWALS_FROZEN,
DEFAULTS.withdrawalsFrozen,
),
btcFundingObserverEnabled: parseBoolean(
process.env.BTC_FUNDING_OBSERVER_ENABLED,
DEFAULTS.btcFundingObserverEnabled,
),
btcFundingObserverBaseUrl:
process.env.BTC_FUNDING_OBSERVER_BASE_URL || DEFAULTS.btcFundingObserverBaseUrl,
fundingObservationStuckMs: parseNumber(
process.env.FUNDING_OBSERVATION_STUCK_MS,
DEFAULTS.fundingObservationStuckMs,
),
opsSentinelEvaluationMs: parseNumber(
process.env.OPS_SENTINEL_EVALUATION_MS,
DEFAULTS.opsSentinelEvaluationMs,
),
opsSentinelPriceStaleMs: parseNumber(
process.env.OPS_SENTINEL_PRICE_STALE_MS,
DEFAULTS.marketReferenceMaxAgeMs,
),
opsSentinelInventoryStaleMs: parseNumber(
process.env.OPS_SENTINEL_INVENTORY_STALE_MS,
DEFAULTS.strategyInventoryMaxAgeMs,
),
opsSentinelFundingCreditPendingMs: parseNumber(
process.env.OPS_SENTINEL_FUNDING_CREDIT_PENDING_MS,
DEFAULTS.opsSentinelFundingCreditPendingMs,
),
opsSentinelFundingStuckMs: parseNumber(
process.env.OPS_SENTINEL_FUNDING_STUCK_MS,
DEFAULTS.fundingObservationStuckMs,
),
opsSentinelIngestMessageStaleMs: parseNumber(
process.env.OPS_SENTINEL_INGEST_MESSAGE_STALE_MS,
DEFAULTS.opsSentinelIngestMessageStaleMs,
),
opsSentinelIngestQuoteStaleMs: parseNumber(
process.env.OPS_SENTINEL_INGEST_QUOTE_STALE_MS,
DEFAULTS.opsSentinelIngestQuoteStaleMs,
),
opsSentinelIngestPublishStaleMs: parseNumber(
process.env.OPS_SENTINEL_INGEST_PUBLISH_STALE_MS,
DEFAULTS.opsSentinelIngestPublishStaleMs,
),
opsSentinelExecutorRelayStaleMs: parseNumber(
process.env.OPS_SENTINEL_EXECUTOR_RELAY_STALE_MS,
DEFAULTS.opsSentinelExecutorRelayStaleMs,
),
opsSentinelHistoryWriterStaleMs: parseNumber(
process.env.OPS_SENTINEL_HISTORY_WRITER_STALE_MS,
DEFAULTS.opsSentinelHistoryWriterStaleMs,
),
opsSentinelDashboardSourceDegradedMs: parseNumber(
process.env.OPS_SENTINEL_DASHBOARD_SOURCE_DEGRADED_MS,
DEFAULTS.opsSentinelDashboardSourceDegradedMs,
),
opsSentinelSelfStaleMs: parseNumber(
process.env.OPS_SENTINEL_SELF_STALE_MS,
DEFAULTS.opsSentinelSelfStaleMs,
),
opsSentinelAnomalyWindowSize: parseNumber(
process.env.OPS_SENTINEL_ANOMALY_WINDOW_SIZE,
DEFAULTS.opsSentinelAnomalyWindowSize,
),
opsSentinelAnomalyQuoteRateCollapseRatio: parseNumber(
process.env.OPS_SENTINEL_ANOMALY_QUOTE_RATE_COLLAPSE_RATIO,
DEFAULTS.opsSentinelAnomalyQuoteRateCollapseRatio,
),
opsSentinelAnomalyReconnectSpikeMultiplier: parseNumber(
process.env.OPS_SENTINEL_ANOMALY_RECONNECT_SPIKE_MULTIPLIER,
DEFAULTS.opsSentinelAnomalyReconnectSpikeMultiplier,
),
opsSentinelContainmentCooldownMs: parseNumber(
process.env.OPS_SENTINEL_CONTAINMENT_COOLDOWN_MS,
DEFAULTS.opsSentinelContainmentCooldownMs,
),
opsSentinelAlertWebhookUrl:
process.env.OPS_SENTINEL_ALERT_WEBHOOK_URL || DEFAULTS.opsSentinelAlertWebhookUrl,
opsSentinelAlertWebhookTimeoutMs: parseNumber(
process.env.OPS_SENTINEL_ALERT_WEBHOOK_TIMEOUT_MS,
DEFAULTS.opsSentinelAlertWebhookTimeoutMs,
),
operatorDashboardAuthMode:
process.env.OPERATOR_DASHBOARD_AUTH_MODE || DEFAULTS.operatorDashboardAuthMode,
operatorDashboardAuthUsername:
process.env.OPERATOR_DASHBOARD_AUTH_USERNAME || DEFAULTS.operatorDashboardAuthUsername,
operatorDashboardAuthPassword:
process.env.OPERATOR_DASHBOARD_AUTH_PASSWORD || DEFAULTS.operatorDashboardAuthPassword,
operatorDashboardAuthRealm:
process.env.OPERATOR_DASHBOARD_AUTH_REALM || DEFAULTS.operatorDashboardAuthRealm,
operatorDashboardQuoteLimit: parseNumber(
process.env.OPERATOR_DASHBOARD_QUOTE_LIMIT,
DEFAULTS.operatorDashboardQuoteLimit,
),
operatorDashboardTradePageSize: parseNumber(
process.env.OPERATOR_DASHBOARD_TRADE_PAGE_SIZE,
DEFAULTS.operatorDashboardTradePageSize,
),
operatorDashboardUpstreamTimeoutMs: parseNumber(
process.env.OPERATOR_DASHBOARD_UPSTREAM_TIMEOUT_MS,
DEFAULTS.operatorDashboardUpstreamTimeoutMs,
),
nearIntentsStatusServicesUrl:
process.env.NEAR_INTENTS_STATUS_SERVICES_URL || DEFAULTS.nearIntentsStatusServicesUrl,
nearIntentsStatusPostsUrl:
process.env.NEAR_INTENTS_STATUS_POSTS_URL || DEFAULTS.nearIntentsStatusPostsUrl,
nearIntentsStatusPostEnumsUrl:
process.env.NEAR_INTENTS_STATUS_POST_ENUMS_URL || DEFAULTS.nearIntentsStatusPostEnumsUrl,
nearIntentsStatusTimeoutMs: parseNumber(
process.env.NEAR_INTENTS_STATUS_TIMEOUT_MS,
DEFAULTS.nearIntentsStatusTimeoutMs,
),
nearIntentsStatusPollMs: parseNumber(
process.env.NEAR_INTENTS_STATUS_POLL_MS,
DEFAULTS.nearIntentsStatusPollMs,
),
notificationNtfyBaseUrl:
process.env.NOTIFICATION_NTFY_BASE_URL || DEFAULTS.notificationNtfyBaseUrl,
notificationNtfyTopic:
process.env.NOTIFICATION_NTFY_TOPIC || DEFAULTS.notificationNtfyTopic,
notificationNtfyToken:
process.env.NOTIFICATION_NTFY_TOKEN || DEFAULTS.notificationNtfyToken,
notificationNtfyTimeoutMs: parseNumber(
process.env.NOTIFICATION_NTFY_TIMEOUT_MS,
DEFAULTS.notificationNtfyTimeoutMs,
),
};
}