feat(clmm): orphaned-position lifecycle, bin_count passthrough, Raydium via Gateway - #217
Open
fengtality wants to merge 3 commits into
Open
feat(clmm): orphaned-position lifecycle, bin_count passthrough, Raydium via Gateway#217fengtality wants to merge 3 commits into
fengtality wants to merge 3 commits into
Conversation
… listing, DB-aware stop, resolve
API-side of the gateway#678 retry-ownership work (canonical design:
docs/retry-architecture.md in the companion gateway PR). Executors created
via the API run in-process with no controller, so the API owns the
"react to a stranded position" role:
- Stop on a terminal executor returns already_terminated with close_type,
position_address, orphaned_position, and hold_reason instead of the 404
dead end #678 hit (terminal executors are popped from memory within one
tick, so "not in memory" almost always means "already terminated").
404 is reserved for ids the DB has never seen.
- Completion flags stranded exposure in the persisted final state:
an involuntary hold (POSITION_HOLD with hold_reason set — an LP close
that exhausted its retries) or a legacy FAILED-with-position gets
orphaned_position: true and an error-level log. Voluntary holds never
match (a successful close clears position_address first).
- GET /executors/positions/orphaned lists recovery candidates
(SQL-filtered to lp_executor; involuntary holds, FAILED-with-position,
and SYSTEM_CLEANUP restarts flagged needs_onchain_reconciliation).
- POST /executors/{id}/resolve-orphan marks a candidate recovered after
the position is closed externally, silencing listings and warnings.
- bots/controllers lp_rebalancer mirror: halt + skip accounting for
executors that ended with a live position (re-creating one would mint a
second position on top of the stranded one).
Validated live on mainnet: forced close-failure cascade terminated as the
involuntary hold, surfaced in the orphan listing with hold_reason,
re-stop returned already_terminated, and resolve-orphan cleared it after
a direct gateway close recovered all funds + rent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HahKfEY9rvKnZijrzUAFSq
This was referenced Aug 13, 2026
Greptile SummaryThe PR adds a durable API-side lifecycle for LP executors that terminate with potentially stranded on-chain positions.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains within the eligible follow-up scope. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| bots/controllers/generic/lp_rebalancer/lp_rebalancer.py | Adds a process-local halt when a newly terminated LP executor still reports an on-chain position and avoids accounting its pool balances as returned funds. |
| database/repositories/executor_repository.py | Adds an SQL-filtered query for recent executor records matching selected close types and an optional executor type. |
| models/executors.py | Extends stop responses with terminal-state metadata and defines orphan-listing response models. |
| routers/executors.py | Exposes endpoints for listing and resolving database-backed orphan candidates. |
| services/executor_service.py | Implements DB-aware stop behavior, orphan persistence and discovery, and explicit resolution of recovered positions. |
| routers/gateway_clmm.py | Replaces the direct Raydium pool lookup with the common Gateway path and forwards an optional bin count. |
| services/gateway_client.py | Adds optional bin-count forwarding to Gateway CLMM pool-information requests. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[LP executor running] --> B{Terminal outcome}
B -->|Normal close| C[Persist terminal state]
B -->|Involuntary hold or failed with position| D[Flag orphan in final state]
B -->|Restart cleanup| E[Mark for on-chain reconciliation]
D --> F[Orphan listing]
E --> F
F --> G[Operator reconciles position externally]
G --> H[Resolve orphan in database]
H --> I[Remove from orphan listing]
D --> J[Process-local controller halt]
J --> K[Explicit controller restart after recovery]
Reviews (3): Last reviewed commit: "refactor(clmm): route Raydium pool-info ..." | Re-trigger Greptile
GET /gateway/clmm/pool-info accepts bin_count and forwards it to Gateway's unified trading/clmm/pool-info, so the per-tick liquidity distribution is reachable for orca, raydium, uniswap and pancakeswap (Meteora always returns its own bins). The response model already carried bins. Requests with bin_count > 0 skip the direct-Raydium-API shortcut: that API returns no bin distribution, and only Gateway computes it from on-chain ticks. Also wraps pre-existing long lines and drops an unused import in routers/gateway_clmm.py — the flake8 pre-commit hook lints the whole file and would not otherwise accept a commit touching it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…her connector /gateway/clmm/pool-info special-cased Raydium: it skipped Gateway entirely, called api-v3.raydium.io directly, and reshaped that response to look like Gateway's. That divergence cost real data — the transform hardcoded active_bin_id to None, bin_step to 1, and bins to [] — and it meant Raydium could not answer bin_count at all, since only Gateway computes the tick distribution. Raydium now takes the same path as meteora/orca/uniswap/pancakeswap. The Raydium API helpers and their aiohttp import go with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
API-side of the gateway#678 retry-ownership work, plus the CLMM pool-info plumbing that goes with it. Canonical design:
docs/retry-architecture.md(in the gateway PR), esp. the two-topology section: executors created via the API run in-process with no controller, so the API owns the "react to a stranded position" role.Orphaned-position lifecycle
already_terminatedwithclose_type,position_address,orphaned_position, andhold_reasoninstead of the 404 dead end #678 hit (terminal executors are popped from memory within one tick, so "not in memory" almost always means "already terminated"). 404 is reserved for ids the DB has never seen.POSITION_HOLDwithhold_reason— an LP close that exhausted its retries) or a legacyFAILED-with-position getsorphaned_position: truepersisted plus an error-level log. Voluntary holds never match (a successful close clearsposition_addressfirst).GET /executors/positions/orphaned: recovery candidates, SQL-filtered tolp_executor— involuntary holds,FAILED-with-position, andSYSTEM_CLEANUPrestarts (flaggedneeds_onchain_reconciliation).POST /executors/{id}/resolve-orphan: mark recovered after the position is closed externally; silences listings and agent warnings.bots/controllerslp_rebalancer mirror: halt + skip accounting for executors that ended with a live position.CLMM pool-info:
bin_count, and Raydium consistencyGET /gateway/clmm/pool-infoacceptsbin_countand forwards it to Gateway's unifiedtrading/clmm/pool-info, making the per-tick liquidity distribution reachable for orca, raydium, uniswap and pancakeswap (Meteora always returns its own bins). The response model already carriedbins.api-v3.raydium.iodirectly, and reshaping that response to imitate Gateway's. That divergence cost real data — the transform hardcodedactive_bin_idtoNone,bin_stepto1, andbinsto[]— and it meant Raydium could not answerbin_countat all, since only Gateway computes the tick distribution. Raydium now takes the same path as every other CLMM connector; the Raydium API helpers and theiraiohttpimport go with it.Companion PRs
docs/retry-architecture.md(in the gateway PR)binCounton unified CLMM pool-infoPOSITION_HOLD, fresh position reads, bounded pending-tx pollingbin_countpassthrough, Raydium routed through Gatewaybin_countonget_pool_info(1.5.8)bin_countonget_pool_infoNote
routers/gateway_clmm.pyalso gains some unrelated line-wrapping and a dropped unused import: the flake8 pre-commit hook lints the whole file and would not otherwise accept a commit touching it.Validation
36 gateway-client contract tests pass. Validated live on mainnet with the companion branches deployed:
hold_reason, re-stop returnedalready_terminated, and resolve-orphan cleared it after a direct gateway close recovered all funds + rent.bin_count=5returns populated bins for orca and raydium through this endpoint;bin_count=0returns none. Raydium via Gateway now reports a realactive_bin_idwhere the bypass reportedNone.🤖 Generated with Claude Code
https://claude.ai/code/session_01Mt84XBEMVxbbyMG8fDxDKj