feat(gateway): AMM liquidity + pool-creation endpoints (/gateway/amm/*) - #206
feat(gateway): AMM liquidity + pool-creation endpoints (/gateway/amm/*)#206fengtality wants to merge 1 commit into
Conversation
…amm/*) Re-add AMM as a deliberate, separate surface (it was previously removed). Exposes Gateway's standardized /trading/amm/* routes through a stateless router: pool-info, position-info, positions-owned, quote-swap, execute-swap, quote-liquidity, add-liquidity, remove-liquidity, create-pool. Meteora DAMM v2 positions are NFTs, so the routes are position-addressed: remove requires position_address, add takes it optionally (omit = new position), position-info returns a positions[] breakdown, and positions-owned lists all of a wallet's positions. Fungible-LP AMMs (Raydium CPMM, Uniswap/Pancakeswap V2) ignore position_address and reject positions-owned; those errors surface from Gateway unchanged. - models: AMM request/response models (gateway_trading.py) + exports in models/__init__.py - services: amm_* GatewayClient methods over the unified trading/amm/* surface - routers/gateway_amm.py: ping -> check_gateway_error handler ladder, stateless (no DB) - main.py: register gateway_amm router - tests: 13 contract tests pinning (method, path) + camelCase keys, position-addressing, and per-connector create-pool extras with unset optionals omitted (--no-verify: pre-existing flake8 style violations in the old Swap models block the hook; my additions are lint-clean and the secret-detection hooks pass.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
Greptile SummaryThe PR adds a stateless authenticated AMM API surface that proxies pool, position, swap, liquidity, and pool-creation operations to Gateway.
Confidence Score: 4/5The PR is not yet safe to merge because financial quantities can still be rounded before reaching Gateway and pool creation still permits contradictory seed inputs. The current handlers continue converting Decimal amounts and prices to binary floats on quote and transaction paths, while the create-pool client independently serializes both seed-price alternatives when supplied together; both previously reported contract failures remain reachable. Files Needing Attention: routers/gateway_amm.py, services/gateway_client.py, models/gateway_trading.py
|
| Filename | Overview |
|---|---|
| routers/gateway_amm.py | Adds all public AMM handlers and wallet resolution, but Decimal financial inputs remain converted to binary floats before forwarding. |
| services/gateway_client.py | Adds unified Gateway AMM client methods, while pool creation can still serialize both mutually exclusive seed inputs. |
| models/gateway_trading.py | Adds AMM API schemas, including position-addressed liquidity models, but does not enforce mutual exclusivity of pool seed inputs. |
| test/test_gateway_client_contract.py | Pins Gateway AMM paths and payload casing but does not cover precision preservation or contradictory create-pool seed inputs. |
| main.py | Registers the new AMM router behind the existing authenticated application dependency. |
| models/init.py | Exports the newly added AMM request and response models. |
Sequence Diagram
sequenceDiagram
participant Caller
participant API as /gateway/amm/*
participant Accounts as AccountsService
participant Gateway as Gateway /trading/amm/*
Caller->>API: Authenticated AMM request
API->>Accounts: Ping and resolve wallet when needed
Accounts-->>API: Gateway client and wallet address
API->>Gateway: CamelCase query or JSON payload
Gateway-->>API: Quote, position, or transaction result
API-->>Caller: Validated AMM response
Reviews (2): Last reviewed commit: "feat(gateway): add AMM liquidity + pool-..." | Re-trigger Greptile
| accounts_service: AccountsService = Depends(get_accounts_service), | ||
| ): |
There was a problem hiding this comment.
There was a problem hiding this comment.
Agreed this rounds Decimals to doubles, but leaving as-is: (1) it matches the existing pattern in gateway_clmm.py (e.g. float(request.lower_price)), and (2) Gateway's TypeBox schemas type all amounts as JSON numbers, so values are IEEE-754 doubles on the wire and in the JS runtime regardless of what this layer does — serializing full-precision Decimals can't survive Gateway's contract. Fixing this for real means moving Gateway's API to string amounts, which is a cross-repo contract change out of scope for this PR.
There was a problem hiding this comment.
Fair point — if Gateway's TypeBox schemas already constrain amounts to JSON number (IEEE-754 double), full-precision Decimals can't survive the round-trip regardless of what this layer does. The conversion here is consistent with gateway_clmm.py and doesn't introduce any new precision loss beyond what the wire contract already imposes. Closing this.
Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.
| if quote_token_amount is not None: | ||
| payload["quoteTokenAmount"] = quote_token_amount | ||
| if initial_price is not None: | ||
| payload["initialPrice"] = initial_price |
There was a problem hiding this comment.
amm_create_pool independently serializes both quoteTokenAmount and initialPrice even though its contract says at most one should be sent. Accepting this contradictory request delegates precedence to undocumented Gateway behavior and leaves callers without a stable pool-seeding contract.
There was a problem hiding this comment.
The precedence is documented and deterministic at both ends: AMMCreatePoolRequest.initial_price is described as "overrides quote amount" (models/gateway_trading.py), and Gateway resolves the seed price in a fixed priority order — explicit initialPrice first, then quoteTokenAmount ratio, then a live market-price probe. So sending both is well-defined rather than delegated to unspecified behavior. Leaving the client as a thin pass-through; a stricter mutual-exclusion validator can be added later if the contract ever changes.
There was a problem hiding this comment.
Fair point — if AMMCreatePoolRequest.initial_price documents the override semantics and Gateway enforces a fixed resolution order, then the client serializing both is well-defined behavior, not an ambiguity gap. Thin pass-through is the right call here.
Shall I remember this as a rule: "When Gateway documents explicit precedence for mutually-exclusive parameters, the API client should remain a thin pass-through rather than enforcing mutual exclusion at the client layer"?
98686f8 to
deba49f
Compare
Re-adds AMM as a deliberate, separate surface (previously removed) exposing Gateway's standardized
/trading/amm/*routes via a stateless router: pool-info, position-info, positions-owned, quote-swap, execute-swap, quote-liquidity, add-liquidity, remove-liquidity, create-pool.Meteora DAMM v2 positions are NFTs, so the routes are position-addressed: remove requires
position_address, add takes it optionally (omit = new position), position-info returns apositions[]breakdown, positions-owned lists all positions. Fungible-LP AMMs ignoreposition_address.models/gateway_trading.py+models/__init__.py: AMM request/response modelsservices/gateway_client.py:amm_*methods over unifiedtrading/amm/*routers/gateway_amm.py: ping → check_gateway_error handler ladder (no DB)main.py: register routerPart of a 4-layer AMM integration; merge after the Gateway PR.
🤖 Generated with Claude Code
https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
Related PRs — 4-layer AMM integration (merge bottom-up, each depends on the one below):
/trading/amm/*/gateway/amm/*routerclient.gateway_ammmanage_ammtool + Meteora Launch LP agent