unrip/IMPLEMENTATION.md
philipp 55ece8f5f0
All checks were successful
deploy / deploy (push) Successful in 34s
Open NEAR Intents request creation turn
Proof: Archive index, implementation proof, and implementation plan now define the approved NEAR Intents EURe-to-BTC request-creation turn with explicit lifecycle, settlement, and safety invariants.

Assumptions: The next turn is approved by the operator and will verify the NEAR Intents request API before any live fund movement; all live submission remains behind repo-owned preflight and explicit operator action.

Still fake: Request API shape is not yet verified, repo-owned request submission is not implemented, and no EURe-to-BTC live request has been created by this planning commit.
2026-04-12 17:39:21 +02:00

156 lines
9.1 KiB
Markdown

# Implementation Turn: NEAR Intents request creation and EURe-to-BTC taker flow
Status: open
Opened: 2026-04-12
## Goal
Build a repo-owned path to create our own NEAR Intents EURe-to-BTC swap request from credited internal inventory, submit it only behind explicit gates, and show truthful request-to-settlement evidence in the dashboard.
## Selected backlog items
- [I017] Repo-owned NEAR Intents request creation and EURe-to-BTC taker flow: create, sign, submit, and settle our own swap requests from credited inventory with truthful dashboard evidence. tags=intents,taker,execution,inventory,settlement
## Design rules
- Treat request creation as a new taker lifecycle, not as an incoming quote-response decision.
- Preflight must be safe and side-effect-free.
- Live submission must be explicit, idempotent, and durably recorded before the relay call.
- Use only spendable credited EURe.
- Keep all ids copyable: request id, idempotency key, intent hash or relay request id, submission id.
- Submitted or relay-accepted does not mean completed.
- Completed requires inventory delta attribution.
## Problem statement
The current system watches the NEAR Intents market and responds to other users' quotes. That is not enough to intentionally convert our EURe inventory to BTC. The operator wants a repo-owned way to create our own request on the intents market and eventually move EURe into BTC, with the same truth standard as the incoming quote lifecycle.
The existing code can sign verifier token_diff payloads for quote responses and can submit quote_response over the solver relay websocket. It does not yet know how to publish a taker request, quote request, or swap intent that asks the market to fill our EURe-to-BTC order.
## Backend changes
### 1. Verify request protocol
- Identify the supported NEAR Intents method for creating our own request using primary code/docs or live non-mutating behavior.
- Determine whether the method uses the existing solver relay websocket, a JSON-RPC HTTP endpoint, or a verifier contract call.
- Determine exact payload fields for EURe-to-BTC exact-in requests.
- Verify signed intent semantics: outgoing EURe, incoming BTC, deadline, nonce, verifier contract, signer.
- Record a hard blocker if the protocol cannot be verified.
### 2. Add request model and schemas
- Add a canonical repo-owned request lifecycle model.
- Add event schemas for at least intent_request_preflight, intent_request_submit_command, intent_request_submission_result, and intent_request_outcome.
- Persist request id, idempotency key, source/destination assets, requested spend, min receive, reference price, slippage, signer account, verifier contract, deadline, nonce, and created/submitted timestamps.
- Keep this model separate from incoming swap_demand, trade_decision, execute_trade, and trade_result events.
### 3. Build preflight service logic
- Load latest spendable EURe inventory from current inventory state or durable snapshot.
- Compute request amount from all spendable EURe minus an explicit reserve if configured, while allowing a smaller operator-specified amount for testing.
- Compute expected BTC from reference price.
- Compute minimum BTC receive from explicit slippage basis points.
- Reject if reference price is stale, inventory is stale, amount is zero, amount exceeds spendable EURe, or signer is not registered.
- Return a draft request object without signing or submitting.
### 4. Build signing/envelope helpers
- Add a helper for taker request signing/envelope construction once the verified protocol is known.
- Reuse buildIntentNonce only if nonce semantics match the request protocol.
- Add deterministic signer tests for the exact signed payload.
- Keep quote-response signing tests unchanged.
### 5. Build gated submit path
- Add a narrow request-executor or extend trade-executor only if responsibilities stay clear.
- Require explicit submit command with preflight id or idempotency key.
- Mark request as submit_requested before the relay/API call.
- Submit with timeout and reconnect-safe client behavior.
- Persist result as submitted, accepted_by_relay, failed, or protocol-specific status.
- Enforce idempotency so duplicate commands cannot submit twice.
### 6. Settlement attribution
- Extend outcome attribution to handle repo-created requests.
- Match settlement from inventory deltas: EURe decrease and BTC increase consistent with submitted request terms.
- Mark unresolved as awaiting_settlement before deadline/grace expires.
- Mark not_filled only after deadline/grace and fresh inventory evidence.
- Mark completed only with durable inventory movement evidence.
### 7. Dashboard and controls
- Add a Funds or Strategy panel for Create BTC request with preflight amount, slippage/minimum BTC receive, dry-run/preflight action, and live submit only after a valid preflight.
- Add a repo-created requests table with request id, created/submitted time, source spend, min receive, state, decisive reason, relay/API response, settlement result, and expandable lifecycle.
- Make request ids and returned intent/relay ids copyable.
- Label live fund movement clearly; no green success label without settlement.
## Data and persistence
- Prefer adding narrow tables or durable event routes for request preflight, submit commands, submission results, and outcomes.
- Preserve raw relay/API responses alongside normalized lifecycle state.
- Include enough fields to replay the request and reason about slippage, deadline, and settlement.
- Do not reuse incoming quote ids as request ids.
## Edge cases
- Missing request API evidence: stop with blocker.
- Signer not registered: block before signing/submission.
- EURe inventory stale or unavailable: block.
- Requested amount exceeds spendable EURe: block.
- Reference price stale: block.
- Slippage missing: block.
- Duplicate idempotency key: return original result, do not submit again.
- Relay timeout: failed or unknown state with durable reason, not completed.
- Relay accepted but no inventory movement: awaiting outcome, then not filled after evidence window.
- Partial fill, if supported: represent explicitly; otherwise block or mark ambiguous until semantics are known.
## Concrete implementation order
### Phase 1. Protocol verification and model
- Inspect primary NEAR Intents request API evidence and current repo clients.
- Decide endpoint/method and payload shape.
- Add request lifecycle constants and schemas.
- Add tests for semantic invariants independent of live API.
### Phase 2. Preflight path
- Implement pure preflight helper for EURe-to-BTC exact-in requests.
- Wire inventory, reference price, signer registration, amount, slippage, and deadline checks.
- Add tests for success, insufficient inventory, stale price, stale inventory, zero amount, and missing signer.
### Phase 3. Signing and submit client
- Implement taker request envelope/signing helper.
- Implement relay/API client method with timeout and error normalization.
- Add deterministic signing tests and mocked client submission tests.
### Phase 4. Durable execution path
- Add request submit command/result event routes and persistence.
- Add idempotency guard.
- Add submission failure and duplicate-submit tests.
### Phase 5. Outcome truth
- Extend request outcome attribution using inventory deltas.
- Add tests for submitted-not-completed, accepted-not-completed, completed with exact settlement, not-filled after deadline, and ambiguous movement.
### Phase 6. Operator UI
- Add preflight/submit controls and request lifecycle table.
- Add copy affordances for request and relay ids.
- Add dashboard tests proving no submitted-only request is labeled successful.
### Phase 7. Deploy and validate
- Run targeted tests plus full npm test.
- Build dashboard bundle.
- Commit with required proof body.
- Push to forgejo/main.
- Validate rollout image, service state, dashboard bootstrap, and live dry-run/preflight.
- If operator explicitly submits live, validate durable request row, submission result, and later settlement or no-fill.
## Test plan
- Request preflight unit tests.
- Request signing/envelope tests.
- Request client timeout/failure tests.
- Idempotency tests.
- Persistence routing tests.
- Outcome attribution tests.
- Dashboard semantic tests.
- Negative tests: submitted != completed; relay accepted != completed; pending EURe cannot be spent; dry-run cannot submit; duplicate submit does not call relay twice; request lifecycle cannot be confused with incoming quote response lifecycle.
## Validation checklist against the proof
- /state or dashboard shows request preflight capability and current spendable EURe.
- A dry-run EURe-to-BTC request can be produced without side effects.
- A live submit path exists only behind explicit operator action.
- Durable request lifecycle rows exist and are visible with copyable ids.
- Settlement outcome remains truthful after submission.
- All services deploy from repo push without manual cluster reconciliation.
## Known fakes allowed at start of this turn
- Request API method is not yet verified.
- Venue-native terminal fill events remain unavailable unless the request API exposes them.
- Fee-complete realized PnL remains unavailable.
- Automatic portfolio optimization remains unavailable.