unrip/archive/implementation/20260518T162356Z-db-backed-asset-registry-and-multi-pair-strategy-configuration-proof.md
philipp fb547f24d9
All checks were successful
deploy / deploy (push) Successful in 48s
fix: scope inventory fetch by submission time window to prevent OOM
Instead of fetching up to 50k inventory snapshots (~442MB), scope the
query to only the time range of the current submission batch with a
15-minute buffer. For a typical 1-hour batch this drops from 50k rows
to ~300 rows, well within the 1280Mi pod memory limit.

The coalesced_at_idx on intent_inventory_snapshots covers the BETWEEN
clause so this remains efficient.

Proof: history-writer OOM kills from refreshQuoteOutcomes inventory fetch
Assumptions: 15min buffer covers the attribution window for all submissions
Still fake: heuristic gap outcomes may attribute trades imprecisely
2026-06-16 17:17:19 +02:00

153 lines
8.8 KiB
Markdown

# Implementation Proof: DB-backed asset registry and multi-pair strategy configuration
Status: open
Opened: 2026-05-12
## Target outcome
The repository must stop treating tradeable assets, active pairs, pair filters, and edge thresholds as environment configuration. Those values must live in Postgres, be visible and auditable in the dashboard, and be reloadable without a deploy.
The system must be able to import the current NEAR Intents supported-token catalog from the 1Click API, persist it durably, and then enable operator-approved pairs from that catalog with per-pair strategy settings.
## Why this is the next architecture test
The previous one-pair model hardcoded BTC/EURe assumptions across config, ingest filtering, pricing, strategy, inventory, dashboard labels, alerts, and taker request creation. That worked for proving one narrow loop, but it blocks the next practical requirement: adding pairs and adjusting edge without editing deployment env vars.
This turn succeeds only if "what can be observed" and "what may trade" are durable runtime data. A new asset or pair must be introduced by DB state and operator controls, not by changing Kubernetes config.
## Scope
- Add DB-backed asset registry sourced from NEAR Intents / 1Click supported tokens.
- Add idempotent importer for `GET https://1click.chaindefuser.com/v0/tokens`.
- Preserve each import run and raw token payload so assets can be re-imported as support changes.
- Add DB-backed enabled pairs with explicit venue, source asset, destination asset, mode, and status.
- Add DB-backed per-pair strategy config: edge bps, max notional, freshness requirements, slippage/default request limits where applicable.
- Replace env-backed pair filter and edge selection in runtime services.
- Seed the current production truth from repo-controlled bootstrap code:
- `nep141:nbtc.bridge.near`
- `nep141:btc.omft.near`
- `nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near`
- current nBTC/EURe pair
- current 49 bps edge
- Preserve current BTC/EURe behavior after migration unless the DB pair config explicitly disables it.
- Make unsupported or unpriced pairs fail closed: observe-only or rejected, never live trading.
## Definitions
- Supported asset: an asset currently returned by the NEAR Intents 1Click tokens endpoint.
- Known asset: any asset ever imported or manually registered in the DB.
- Enabled pair: a directed pair the operator has approved for quote ingestion and/or trading.
- Pair mode: `observe_only`, `maker`, `taker`, or `both`.
- Pair strategy version: the immutable config snapshot used by a decision, command, or request.
- Retired asset: a known asset not present in the latest import, retained for history and inventory visibility.
## Assumptions
- The 1Click tokens endpoint is the primary machine-readable source for currently supported NEAR Intents assets.
- The endpoint can change over time, so importer output must be append/audit friendly.
- Env vars remain valid only for infra and secrets: database URL, Kafka/RPC URLs, API keys, signer private key, service ports.
- Pair and edge config must not be set by env vars in production.
- Broad "any pair" support still requires a fresh reference price route and spendable inventory for that pair before trading can be armed.
## Turn-shaping rules
- Do not enable live trading for newly imported pairs by default.
- Do not delete assets when they disappear from the live token list; mark them unsupported/retired and keep historical records.
- Do not remove existing BTC/EURe history compatibility.
- Do not widen live-funds risk without explicit operator enablement.
- Do not treat a token being supported by 1Click as proof that we have inventory, pricing, liquidity, or safe execution for it.
- Do not introduce env vars for pair selection, edge thresholds, or active trading assets.
## Non-goals
- No automatic pair discovery to live trading.
- No generalized portfolio optimizer.
- No new venue beyond NEAR Intents.
- No realized net PnL or fee-complete accounting.
- No automatic recurring rebalancer.
- No live taker submission expansion unless it uses the new pair config and remains explicitly gated.
- No guarantee that every supported-token pair has solver liquidity.
## Required operator behavior
### Asset catalog truth
The operator must be able to see:
- latest supported-token import status
- import source URL and fetched_at timestamp
- token count
- added, updated, unchanged, and retired counts
- asset id, symbol, decimals, blockchain, contract address, price, priceUpdatedAt
- raw payload for imported tokens
- whether an asset is supported, known, enabled for inventory tracking, or retired
### Pair configuration truth
The operator must be able to see:
- enabled directed pairs and their modes
- pair status: disabled, observe_only, maker, taker, both
- asset metadata for each side
- edge bps and max notional for the active strategy version
- price route availability and freshness policy
- last decision/config version using the pair
- whether the pair can trade or is blocked, with a decisive reason
### Trading safety truth
Every decision, command, quote response, and repo-created request must persist:
- pair id
- pair config version
- edge bps used
- max notional used
- asset decimals and reference price id used
- reason if the pair was unsupported, disabled, unpriced, stale, or inventory-blocked
## Semantic invariants
The implementation and tests must enforce:
- pair/edge/env vars are not required for production trading behavior
- DB config absence fails closed
- imported support does not imply trading enablement
- retired assets remain visible for old balances and history
- each trade decision stores the exact pair config version used
- a pair cannot trade without a fresh reference price route
- a pair cannot trade without known asset decimals for both sides
- duplicate asset imports are idempotent
- updating edge creates a new strategy config version instead of mutating historical decision meaning
- dashboard labels come from the DB asset registry, not hardcoded BTC/EURe config
## Definition of done
- DB schema and bootstrap seed current production assets/pair/edge.
- Supported-token importer fetches 1Click tokens, upserts assets, records an import run, and marks missing assets retired without deleting them.
- Runtime config loader provides assets, enabled pairs, and strategy config to ingest, strategy, dashboard, alerts, and outcome attribution.
- NEAR Intents ingest uses DB-backed enabled pairs instead of `NEAR_INTENTS_PAIR_FILTER`.
- Strategy uses per-pair DB edge config instead of `STRATEGY_GROSS_THRESHOLD_PCT`.
- Current nBTC/EURe maker behavior remains functional after migration.
- Dashboard exposes asset import status and pair strategy config.
- Deployment config no longer carries trading asset/pair/edge env vars.
- Tests prove fail-closed behavior, import idempotency, config versioning, and current-pair compatibility.
- The result is deployed through repo workflow and validated against live service state.
## Validation evidence required
- Unit tests for supported-token import normalization and idempotent upsert.
- Unit tests for retired asset handling.
- Unit tests for DB pair config loading and fail-closed missing-config behavior.
- Unit tests proving edge changes version strategy config and historical decisions keep the old version.
- Strategy tests for current nBTC/EURe pair using DB config.
- Ingest tests proving pair filtering comes from DB pair set.
- Dashboard tests proving labels/config come from DB asset registry.
- Live importer evidence showing current token count and presence of nBTC, legacy OMFT BTC, and EURe.
- Live dashboard/bootstrap evidence showing current pair and 49 bps edge loaded from DB.
- Deployment evidence showing pair/edge env vars removed from repo-owned production config.
## Failure conditions
- A service still needs pair or edge env vars to trade the current pair.
- A newly imported asset becomes trade-enabled by default.
- Missing DB config causes uncontrolled all-pair ingestion or trading.
- Retired assets vanish from historical dashboard/inventory views.
- Decisions do not persist pair config version.
- The importer cannot be rerun safely.
- The dashboard or alerts still assume one BTC/EURe active pair after migration.
## Current real before this turn
- The repo can ingest NEAR Intents quote flow for one configured pair.
- The repo can maintain internal inventory for the configured BTC/EURe assets.
- The repo can publish maker quote responses and attribute outcomes for the current pair.
- The dashboard can show current funds, quote lifecycle, and service state.
- The live 1Click tokens endpoint currently returns token records including nBTC, legacy BTC OMFT, and EURe.
## Deliberately not built by this proof
- Fully automated pair profitability discovery.
- Liquidity-depth probing for every possible pair.
- Cross-venue routing.
- Fee-complete realized PnL.
- Autonomous live trading enablement for imported assets.