diff --git a/ARCHIVE.md b/ARCHIVE.md index 5469016..4967a17 100644 --- a/ARCHIVE.md +++ b/ARCHIVE.md @@ -30,3 +30,4 @@ Legacy note: - 2026-04-08: opened implementation turn `quote-lifecycle-truth-and-execution-explanation` from backlog items I021. - 2026-04-09: opened implementation turn `execution-outcome-truth-and-settled-attribution` from backlog items I017, I018. - 2026-04-10: opened implementation turn `settlement-aware-strategy-and-inventory-skew-controls` from backlog items I015. +- 2026-04-12: opened implementation turn `near-intents-request-creation-and-eure-to-btc-taker-flow` from backlog items I017. diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index c6b72a8..11419ff 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -1,5 +1,156 @@ -# Implementation Turn +# Implementation Turn: NEAR Intents request creation and EURe-to-BTC taker flow -Status: idle +Status: open +Opened: 2026-04-12 -No approved implementation turn is active yet. +## 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. diff --git a/PROOF.md b/PROOF.md index 71baf39..35c87be 100644 --- a/PROOF.md +++ b/PROOF.md @@ -1,5 +1,133 @@ -# Implementation Proof +# Implementation Proof: NEAR Intents request creation and EURe-to-BTC taker flow -Status: idle +Status: open +Opened: 2026-04-12 -No approved implementation proof is active yet. +## Target outcome +The repository must be able to create our own NEAR Intents EURe-to-BTC swap request from credited internal inventory, submit it through repo-owned code, and explain the full request lifecycle from preflight through settlement truth. + +For each repo-created request the operator must be able to answer: +- which asset and amount we intended to spend +- which asset and minimum amount we expected to receive +- which signer, verifier contract, nonce, deadline, slippage, and idempotency key were used +- whether the request was drafted, blocked, submitted, accepted by relay, failed, awaiting settlement, not filled, or completed +- whether completed means durable inventory movement, not relay acceptance +- how much BTC was received and how much EURe was spent, if settlement is proven + +## Why this is the next architecture test +The existing system can observe incoming NEAR Intents quote requests and respond as a solver or maker. That path has not produced fills at 1.49%, 0.99%, or 0.49% in recent live validation, and it cannot intentionally convert our EURe inventory into BTC. + +The next false path would be manually moving funds or adding a button that submits opaque live requests without durable preflight, request, and settlement evidence. This turn is successful only if the system can create requests as a first-class, auditable repo-owned flow instead of treating live fund movement as an off-system action. + +## Scope +- [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 +- Active venue only: NEAR Intents. +- Active direction: credited internal EURe to BTC. +- Use credited spendable internal inventory only. Pending funding remains non-spendable. +- Build the request path with dry-run/preflight first, then gated live submission. +- Actual live submission requires explicit operator control and must be recorded durably. + +## Assumptions +- NEAR Intents exposes a supported request or quote publication method through the solver relay or another documented endpoint callable with our existing API key and verifier signer. +- The correct taker intent can be represented as a signed verifier token_diff payload or a documented request envelope whose semantics can be proven before live submission. +- Internal inventory snapshots are fresh enough to enforce spendable EURe and settlement deltas. +- BTC minimum receive can be derived from reference price plus explicit slippage or minimum-out policy. +- The user's intent is to build the capability to move EURe into BTC; live all-EURe execution remains behind an explicit final operator action in the repo-owned UI or API. + +## Turn-shaping rules +- Do not manually move funds. +- Do not submit an all-EURe live request until repo-owned preflight, durable request logging, and settlement attribution are implemented and the operator explicitly triggers that live request. +- Do not use pending or uncredited EURe. +- Do not label relay acceptance as completed settlement. +- Do not hide slippage, minimum receive, deadline, nonce, signer, or request id. +- If the NEAR Intents request API cannot be verified from primary evidence or live dry-run behavior, stop and record the blocker instead of inventing a protocol. +- Keep maker quote-response logic intact unless the new taker flow proves it should be paused or separated. + +## Non-goals +- No new venue. +- No external wallet or manual bridge action. +- No automatic recurring rebalancer. +- No realized net PnL claim without fee and cost attribution. +- No tax or accounting treatment. +- No broad multi-asset request builder beyond EURe-to-BTC. + +## Required operator behavior + +### Request preflight truth +Before submission, the operator must see: +- spendable EURe available +- requested EURe spend amount +- BTC reference price +- slippage or minimum-out rule +- expected BTC receive and minimum BTC receive +- deadline and nonce policy +- exact signer account and verifier contract +- whether this is dry-run only or live-submit capable + +### Request lifecycle truth +For each repo-created request, the dashboard must show: +- request id, copyable +- idempotency key, copyable +- intent hash or relay request id if returned, copyable +- created_at, submitted_at, resolved_at if known +- state: draft, blocked, submitted, accepted_by_relay, failed, awaiting_settlement, not_filled, completed +- decisive reason for blocks, failures, or no-fill +- settlement evidence if completed + +### Settlement truth +Completed requires durable asset movement evidence: +- EURe spend delta and BTC receive delta from inventory snapshots +- attribution method and caveat if heuristic +- submitted-only and relay-accepted rows remain separate from completed +- portfolio-vs-hold movement remains separate from realized trade PnL + +## Semantic invariants +The implementation and tests must enforce at least: +- request submitted != completed +- relay accepted != settled inventory movement +- pending EURe cannot be spent +- insufficient spendable EURe blocks before signing or submission +- slippage and minimum-out must be explicit and persisted +- duplicate idempotency key cannot produce duplicate live submissions +- dry-run request cannot accidentally submit +- completed request rows require durable settlement evidence +- request-creation flow is distinct from incoming quote-response flow + +## Definition of done +- The repo contains a verified NEAR Intents request-creation client or a recorded blocker proving the venue path is unavailable. +- A request preflight API computes amount, min-out, deadline, nonce policy, signer, verifier, and inventory checks from durable/current data. +- A gated live submission API exists only after preflight and records durable request, submission, and result events. +- The dashboard shows repo-created request rows separately from incoming quote-response rows, with copyable ids and lifecycle reasons. +- Settlement attribution handles repo-created requests without treating relay acceptance as completion. +- Regression tests cover request signing/envelope semantics, inventory blocks, dry-run safety, idempotency, submission failure, submitted-not-completed, and completed-only-with-settlement. +- The result is deployed through the repo workflow and validated against live service state. + +## Validation evidence required +- Unit tests for request preflight and minimum-out/slippage math. +- Unit tests for signed request or request envelope construction using deterministic signer fixtures. +- Unit tests proving insufficient EURe blocks before signing/submission. +- Unit tests proving submitted/accepted requests do not count as completed without inventory deltas. +- Live dry-run/preflight evidence for current credited EURe inventory. +- If live submission is explicitly triggered, durable DB evidence for request, submission result, and later settlement or no-fill. +- Dashboard bootstrap evidence showing the new request lifecycle row with copyable ids and truthful state. + +## Failure conditions +- Live funds are moved outside repo-owned code. +- A request is submitted without durable preflight and request records. +- The UI claims BTC was bought from relay acceptance alone. +- A dry-run path can submit. +- Pending funding is treated as spendable. +- The implementation cannot prove the NEAR Intents request API shape and still proceeds. + +## Current real before this turn +- The repo has verifier signing for quote-response token_diff payloads. +- The repo has a solver relay websocket client and quote-response submission path. +- Credited internal BTC/EURe inventory is synced durably. +- Quote, decision, command, submission result, and outcome attribution records exist for incoming quote-response flow. +- The dashboard distinguishes submitted, not-filled, completed, rejected, and blocked rows for incoming quote responses. + +## Deliberately not built by this proof +- General portfolio optimizer. +- Automatic all-in rebalancing loop. +- Fee-complete realized PnL. +- Venue-native terminal fill ingestion unless the request API provides it directly.