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
207 lines
9.4 KiB
Markdown
207 lines
9.4 KiB
Markdown
# 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:
|
|
|
|
```text
|
|
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.near`
|
|
- `nep141:btc.omft.near`
|
|
- `nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near`
|
|
|
|
## Backend changes
|
|
|
|
### 1. Add config schema
|
|
Add tables through the tracked schema path:
|
|
|
|
```sql
|
|
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, upserts `trading_assets`, and writes `supported_asset_import_runs`.
|
|
- Mark previously supported assets as `supported=false` and `retired_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-ingest` loads 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_configs` row 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`/`tradingEure` assumptions 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_assets` for tracked assets.
|
|
- Dashboard shows balances for known/tracked assets including retired assets.
|
|
- Funding/deposit observations label assets from DB metadata.
|
|
- Assets may be `supported=false` but 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.yaml` after 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.
|