All checks were successful
deploy / deploy (push) Successful in 48s
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
9.4 KiB
9.4 KiB
Implementation Turn: DB-backed asset registry and multi-pair strategy configuration
Status: open Opened: 2026-05-12
Goal
Move supported assets, enabled pairs, pair filters, and per-pair edge/trading limits out of environment variables and into durable Postgres state, with a re-importable NEAR Intents asset catalog and fail-closed live trading behavior.
Selected backlog items
- none selected; this turn was opened directly from the approved operator request on 2026-05-12.
Design rules
- DB state is the source of truth for assets, enabled pairs, edge, limits, and pair modes.
- Env remains only for infra/secrets/service wiring.
- Importing an asset never enables trading by itself.
- Pair config updates are versioned. Historical decisions must remain explainable.
- Services fail closed if DB config is missing, stale, invalid, or internally inconsistent.
- Current nBTC/EURe behavior must survive the migration before any additional pair trades.
External source
The supported asset catalog comes from the NEAR Intents 1Click tokens endpoint:
GET https://1click.chaindefuser.com/v0/tokens
The docs describe this endpoint as the source for supported token assetId values. A live check on 2026-05-12 returned an array of 163 token records and included:
nep141:nbtc.bridge.nearnep141:btc.omft.nearnep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near
Backend changes
1. Add config schema
Add tables through the tracked schema path:
supported_asset_import_runs
trading_assets
trading_pairs
pair_strategy_configs
pair_price_routes
pair_config_audit_log
Minimum fields:
supported_asset_import_runs: run id, source URL, fetched_at, status, token_count, added_count, updated_count, retired_count, raw response hash, error.trading_assets: asset id, venue, symbol, label, decimals, blockchain, contract address, latest price, price updated at, supported, retired_at, enabled_for_inventory, raw payload, updated_at.trading_pairs: pair id, venue, asset_in, asset_out, mode, enabled, status, created_at, updated_at.pair_strategy_configs: 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, created_at, created_by, reason.pair_price_routes: route id, pair id, source, base asset id, quote asset id, route config JSON, max age, enabled.pair_config_audit_log: audit id, entity type, entity id, action, old value, new value, changed_at, changed_by, reason.
2. Build supported-token importer
- Add a pure normalizer for 1Click token records.
- Add an idempotent importer that fetches
/v0/tokens, validates shape, upsertstrading_assets, and writessupported_asset_import_runs. - Mark previously supported assets as
supported=falseandretired_at=<run time>when missing from the latest import. - Keep raw payloads and source metadata.
- Add an operator-safe command/API to rerun the importer.
- Add tests for success, duplicate import, token update, asset retirement, malformed response, and network failure.
3. Seed current production truth
- Seed current nBTC, legacy OMFT BTC, and EURe assets if absent.
- Seed both directed nBTC/EURe pair rows needed by maker quote response.
- Seed the active strategy config at 49 bps.
- Seed current max notional/deadline/freshness settings from existing production defaults.
- Keep legacy OMFT BTC inventory-visible but not active for maker trading unless explicitly enabled.
4. Runtime DB config loader
- Add a loader module that returns:
- asset registry map
- enabled pair set
- pair strategy config by pair
- tracked asset ids
- supported/retired flags
- Cache briefly but refresh without restart.
- Expose config load state in service
/state. - Fail closed when DB is unreachable or config is invalid.
- Store config version metadata in emitted decisions and commands.
5. Replace env-backed pair filtering
- Remove runtime dependency on
NEAR_INTENTS_PAIR_FILTER. near-intents-ingestloads enabled observed pairs from DB.- Ingest should preserve raw quote data but only normalize/publish pairs approved for observation/trading.
- Pair updates must apply without redeploy.
- Keep a safe disabled state when no pairs are configured.
6. Replace env-backed strategy edge
- Remove runtime dependency on
STRATEGY_GROSS_THRESHOLD_PCT. - Strategy selects the active
pair_strategy_configsrow for the incoming quote pair. - Decisions include
pair_id,pair_config_id,pair_config_version,edge_bps, and active limits. - Unsupported/disabled/unpriced pairs emit explicit rejected decisions, not silent drops where practical.
- Existing nBTC/EURe math remains the first compatibility target.
7. Generalize asset and pair math
- Replace
tradingBtc/tradingEureassumptions in strategy with pair assets from DB. - Use DB decimals for amount conversion.
- Preserve current BTC/EURe reference-price support first.
- Block pairs whose price route is missing or stale.
- Keep pair direction explicit instead of inferring BTC/EURe-only names.
8. Price route model
- Current market reference is BTC/EUR-specific.
- Add DB price routes before enabling non-BTC/EURe trading.
- For this turn, support the current nBTC/EURe route and make other pairs blocked with
price_route_missing. - Persist enough price-route metadata so later sources can be added without another env-based pair model.
9. Inventory and funding visibility
- Inventory sync uses DB
trading_assetsfor tracked assets. - Dashboard shows balances for known/tracked assets including retired assets.
- Funding/deposit observations label assets from DB metadata.
- Assets may be
supported=falsebut still inventory-visible.
10. Dashboard controls
- Add an asset catalog section:
- import status
- import button/control
- counts for supported/retired/known assets
- searchable asset table
- Add a pair config section:
- pair rows with mode/status
- active strategy config and edge bps
- price route status
- controls to enable observe-only and update edge
- Live trading enablement must remain explicit and separated from import.
- Show pair config version in quote lifecycle rows.
11. Alerts and health
- Runtime health uses DB active pair set instead of a single
activePair. - Alerts must include pair id where applicable.
- Missing DB config or invalid active pair config becomes a critical blocked state for trading services.
- NEAR upstream incident relevance should be scoped to DB tracked assets/chains.
12. Deployment config cleanup
- Remove pair/asset/edge env vars from
deploy/k8s/base/unrip.yamlafter DB seed and runtime loading are in place. - Keep infra/secrets env vars.
- Ensure a repo push deploys the whole change without manual database editing.
Concrete implementation order
Phase 1. Schema and seed
- Add DB schema and helper functions.
- Add seed routine for current nBTC/EURe production config.
- Add tests proving seed is idempotent.
Phase 2. Asset importer
- Implement 1Click token fetch/normalize/import.
- Add CLI/control path for re-import.
- Add tests for import and retirement semantics.
Phase 3. Runtime config loader
- Implement DB loader and fail-closed validation.
- Convert asset registry consumers that only need labels/decimals.
- Add tests for missing/invalid config.
Phase 4. Ingest migration
- Replace env/file pair filter with DB pair set.
- Preserve current pair behavior.
- Add tests for pair update and no-config disabled behavior.
Phase 5. Strategy migration
- Load pair strategy config from DB.
- Remove global env edge use from runtime.
- Persist pair config version in decisions/commands.
- Add current-pair compatibility and edge-version tests.
Phase 6. Dashboard and controls
- Add asset import and pair config surfaces.
- Add controls for re-import and observe-only/pair edge update.
- Add tests proving dashboard data comes from DB.
Phase 7. Deployment cleanup and validation
- Remove asset/pair/edge env vars from deployment config.
- Run targeted tests and full test suite.
- Build dashboard bundle.
- Deploy through repo workflow.
- Validate live importer, current pair config, quote ingest, decisions, and dashboard bootstrap.
Test plan
- Asset import normalizer tests.
- Import idempotency tests.
- Retired asset tests.
- Schema/seed idempotency tests.
- Runtime config loader tests.
- Fail-closed missing DB config tests.
- Ingest DB pair filter tests.
- Strategy per-pair edge tests.
- Strategy config versioning tests.
- Dashboard asset/pair config tests.
- Deployment config static test proving pair/edge env vars are absent.
Validation checklist against the proof
- DB contains current assets and current nBTC/EURe pair.
- Supported-token importer can rerun and record a new import run.
- Current active pair and 49 bps edge load from DB.
- NEAR Intents ingest no longer depends on
NEAR_INTENTS_PAIR_FILTER. - Strategy no longer depends on
STRATEGY_GROSS_THRESHOLD_PCT. - Dashboard shows asset import status and pair strategy config.
- New imported assets are not trade-enabled by default.
- Current pair still emits decisions and quote responses when armed.
- All services deploy from repo push.
Known fakes allowed at start of this turn
- Only current BTC/EURe pricing route is real.
- Additional imported pairs may be observe-only or blocked until price routes exist.
- Venue-native terminal fills remain unavailable unless existing paths already provide them.
- Fee-complete realized PnL remains unavailable.