Skip to content

feat(meteora): add DAMM v2 (cp-amm) AMM connector - #671

Open
fengtality wants to merge 10 commits into
developmentfrom
feat/meteora-damm-v2
Open

feat(meteora): add DAMM v2 (cp-amm) AMM connector#671
fengtality wants to merge 10 commits into
developmentfrom
feat/meteora-damm-v2

Conversation

@fengtality

@fengtality fengtality commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Meteora DAMM v2 (constant-product cp-amm) integration under /connectors/meteora/amm/*, mirroring the Raydium AMM connector and backed by @meteora-ag/cp-amm-sdk. Meteora's existing DLMM connector stays as clmm; this adds amm as a second trading type.

Endpoints

Endpoint Notes
pool-info, position-info Reserves, price, base fee %; wallet's aggregated position liquidity
quote-swap, execute-swap Exact-in (SELL) / exact-out (BUY) via getQuote2/swap2
quote-liquidity, add-liquidity, remove-liquidity Deposit quote; add to/open an NFT position; remove a %
create-pool Create + seed a pool (generic CreatePool schema added to amm-schema.ts)

DAMM v2 custom features (see docs/connectors/meteora-damm-v2.md)

DAMM v2 diverges from a fungible-LP AMM; the doc records each difference, how it maps onto the shared AMM interface, and proposed follow-ups:

  • Positions are NFTs (multiple per pool) → add/remove operate on the wallet's largest position; position-info aggregates. Position-addressed routes proposed.
  • sqrt-price accounting → all math via SDK helpers.
  • Config-driven pool creation: create-pool requires an explicit configAddress because many permissionless configs are launch configs with ~99% starting fees (Gateway won't auto-select and foot-gun users).
  • Market-price seeding: if neither initialPrice nor quoteTokenAmount is given, the seed price is fetched from the unified swap router (/trading/swap/quote) so pools open on-market instead of being immediately arbitraged/sniped. No market to price against → clear error, never a guess.
  • Base + dynamic fees, Token-2022, and locks/vesting handled or explicitly scoped out.

Testing

  • Unit tests mirror the Raydium AMM suite (pool-info, quote-swap BUY/SELL, quote-liquidity, create-pool guard). Full Meteora suite green (51 tests); tsc + lint clean.
  • Validated live on mainnet with a real wallet: create → add → swap (SELL + BUY) → remove, all confirmed. Live testing surfaced the off-market-seeding/sniping issue, which motivated the market-price default above.

🤖 Generated with Claude Code


Related PRs — 4-layer AMM integration (merge bottom-up, each depends on the one below):

  1. Gateway: feat(meteora): add DAMM v2 (cp-amm) AMM connector #671 — DAMM v2 (cp-amm) connector + unified /trading/amm/*
  2. hummingbot-api: feat(gateway): AMM liquidity + pool-creation endpoints (/gateway/amm/*) hummingbot-api#206/gateway/amm/* router
  3. SDK: feat(gateway): GatewayAMMRouter (client.gateway_amm) hummingbot-api-client#24client.gateway_amm
  4. condor: feat(amm): manage_amm tool + Meteora Launch LP agent condor#192manage_amm tool + Meteora Launch LP agent

fengtality and others added 2 commits August 3, 2026 20:32
Adds a Meteora DAMM v2 integration under /connectors/meteora/amm/*, mirroring
the Raydium AMM connector and backed by @meteora-ag/cp-amm-sdk.

Endpoints: pool-info, position-info, quote-swap, execute-swap, quote-liquidity,
add-liquidity, remove-liquidity, and create-pool (with a generic CreatePool
schema added to amm-schema.ts).

DAMM v2's custom features are mapped onto the AMM interface (NFT positions,
sqrt-price accounting, config-driven pool creation, base/dynamic fees, Token-2022,
locks/vesting) and documented — with proposed enhancements — in
docs/connectors/meteora-damm-v2.md. create-pool requires an explicit configAddress
because many permissionless configs are launch configs with ~99% starting fees.

Unit tests mirror the Raydium AMM suite (pool-info, quote-swap BUY/SELL,
quote-liquidity, create-pool guard). typecheck + lint clean; full Meteora suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
create-pool now resolves the initial price in priority order: explicit initialPrice,
then explicit quoteTokenAmount ratio, else the live market price fetched from the unified
swap router (/trading/swap/quote → Jupiter on Solana). Only baseTokenAmount is required;
the quote side is derived. If the base token has no market to price against, it throws a
clear error asking for initialPrice/quoteTokenAmount rather than guessing.

This prevents opening a pool off-market and being immediately arbitraged/sniped (as observed
in live testing: a pool seeded at 0.001 was repriced to ~0.0039 by MEV bots within one slot;
the router quote returns 0.00385, i.e. the correct on-market seed price).

The seed price is returned as `price` in CreatePoolResponse. quoteTokenAmount is now optional;
initialPrice added to the request schema. Doc updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
@rapcmia rapcmia moved this to Backlog in Pull Request Board Aug 4, 2026
@rapcmia rapcmia self-assigned this Aug 4, 2026
@rapcmia rapcmia added this to the v2.17 milestone Aug 4, 2026
fengtality and others added 7 commits August 4, 2026 20:17
…ed /trading/amm/create-pool

Adds pool creation across AMM connectors, matching the Meteora DAMM v2 create-pool:
- Raydium: cpmm.createPool (CP-Swap), single-tx, dynamic fee-config from the Raydium API,
  mainnet/devnet program selection, market-price seeding (anti-snipe).
- Uniswap: V2 router.addLiquidity auto-creates the pair (fixed 0.30% fee), pair address read
  from the factory; ETH/WETH via addLiquidityETH; allowance checks; market-price seeding.
- Unified POST /trading/amm/create-pool dispatches on connector (meteora|raydium|uniswap),
  carrying per-connector optionals (configAddress / feeConfigIndex+openTime / gasPrice+maxGas).

All three share the generic CreatePoolResponse. Seed price priority everywhere:
initialPrice -> quoteTokenAmount ratio -> live market price from the unified swap router.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
…/* for all 7 operations

Standardizes Meteora/Raydium/Uniswap AMM route files to export a uniform network-based
function per operation (getPoolInfo, getPositionInfo, quoteSwap, executeSwap, quoteLiquidity,
addLiquidity, removeLiquidity), each returning the shared amm-schema type — mirroring how the
unified CLMM routes consume connectors.

Adds unified cross-connector routes under /trading/amm (pool-info, position-info, quote-swap,
execute-swap, quote-liquidity, add-liquidity, remove-liquidity) that dispatch on `connector`,
alongside the existing create-pool. Uniswap V2 wrappers derive the quote token from the pair
(token0/token1); Uniswap create-pool validation errors now return 400 (not 500).

Updates the unified swap router (trading/swap/{quote,execute}) to the new connector signatures.

Tests: adds create-pool unit tests for Raydium (CPMM) and Uniswap (V2) and a unified-dispatch
test; existing AMM + swap tests pass (54 total).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
…ess and drop quoteToken

CLMM swaps are pool-addressed, so the counter ("quote") token is fully determined by
poolAddress + baseToken. Standardizes the exported quoteSwap/executeSwap wrappers for
Meteora/Raydium/Uniswap CLMM to the signature (network, [walletAddress,] poolAddress,
baseToken, side, amount, slippagePct?) — matching the AMM connectors — and derives the
counter token from the pool via a per-connector resolveCounterToken helper
(dlmmPool.tokenX/Y, poolInfo.mintA/B, pool-info base/quote).

Updates the unified swap router (trading/swap/{quote,execute}) CLMM call sites accordingly,
and the Meteora/Raydium execute-swap route handlers + the Uniswap execute route (which now
resolves the pool via findDefaultPool before calling the poolAddress-required function).

An unknown base token not in the pool now returns 400 (was 404). Tests updated to
argument-based token mocks; all CLMM + trading suites pass (69).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
…3 + unified /trading/clmm/create-pool

Adds pool creation to all three CLMM connectors. create-pool CREATES + INITIALIZES a pool at
an initial price (no position seeded — concentrated-liquidity positions need a range, opened
separately via open-position). Initial price priority: initialPrice -> live market price from
the unified swap router (anti-off-market default). Reuses the shared CreatePoolResponse.

- Meteora DLMM: DLMM.createCustomizablePermissionlessLbPair2 (Token-2022 aware); activeId
  derived from initialPrice via the SDK's own getPricePerLamport/getBinIdFromPrice math;
  canonical mint ordering with price inversion; binStep + feeBps required.
- Raydium CLMM: raydiumSDK.clmm.createPool with an ammConfig from api.getClmmConfigs()
  (ammConfigIndex), initialPrice as Decimal; SDK handles mint ordering + price inversion.
- Uniswap V3: NonfungiblePositionManager.createAndInitializePoolIfNecessary (added factory
  getPool, pool slot0, and NFT-manager ABIs); initialPrice -> sqrtPriceX96 with decimal +
  token0/token1 orientation handling; fee tier param (100/500/3000/10000).

Unified POST /trading/clmm/create-pool dispatches on connector, carrying per-connector extras
(binStep/feeBps, ammConfigIndex, fee/gasPrice/maxGas). Tests: per-connector validation +
unified dispatch; full suite green (104).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
…p/executeSwap

Extends the CLMM swap standardization to the remaining pool-addressed connectors: quoteSwap/
executeSwap now require poolAddress and drop quoteToken (derived from the pool via a per-connector
resolveCounterToken) — orca via getWhirlpool tokenMintA/B, pancakeswap via getPancakeswapPoolInfo,
pancakeswap-sol via getClmmPoolInfo. Swap-router call sites updated. Router-only connectors
(0x/dflow/jupiter/okx/titan) keep quoteToken by design (no pool).

All Gateway pool-based DEX swap functions now share one signature. tsc clean; 235 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
…l for orca/pancakeswap/pancakeswap-sol

Finishes standardizing every pool-based Gateway DEX so all share one interface.

Standardization:
- PancakeSwap AMM: standardized the 7 ops to network-based signatures (getPoolInfo, getPositionInfo,
  quoteSwap, executeSwap, quoteLiquidity, addLiquidity, removeLiquidity) mirroring uniswap AMM,
  and wired pancakeswap into the unified /trading/amm/* dispatch (+ swap-router AMM branches).

create-pool (create + initialize at price; no position seeded):
- Orca (Whirlpools): client.createPool with tickSpacing + initialTick (PriceMath), PoolUtil.orderMints.
- PancakeSwap AMM (V2 fork): router.addLiquidity auto-create; CLMM (V3 fork):
  NonfungiblePositionManager.createAndInitializePoolIfNecessary, fee tiers 100/500/2500/10000
  (+ V3 factory/pool/NFT-manager ABIs).
- pancakeswap-sol CLMM: manual create_pool instruction from the bundled IDL (discriminator + PDA
  seeds decoded from IDL bytes), sqrt_price_x64 from priceToSqrtPriceX64, explicit ammConfig.
- Unified /trading/{amm,clmm}/create-pool dispatch extended to all six pool-based connectors.

Router-only connectors (0x/dflow/jupiter/okx/titan) are excluded by design (no pool). All connector
+ trading tests pass (511); tsc/lint/build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
…s, add positions-owned)

DAMM v2 positions are NFTs, not fungible LP; a wallet may hold several per
pool, each an independent asset differing in size, lock state, and fees. The
prior AMM routes aggregated on read but silently acted on the largest position
on write, so "remove 100%" was not a true exit when several existed.

Make the Meteora AMM routes position-addressed (mirroring CLMM):
- remove-liquidity now REQUIRES positionAddress; percentage applies to that
  position (found via the owner-filtered getUserPositions, which also proves
  ownership + pool membership).
- add-liquidity takes an OPTIONAL positionAddress: provide to add to that
  position, omit to open a NEW position NFT (never silently the largest).
- position-info returns the pool aggregate PLUS a positions[] breakdown
  (positionAddress, lpTokenAmount, base/quote per NFT) — the discovery path.
- new positions-owned route lists all of a wallet's DAMM v2 positions across
  pools (getPositionsByUser grouped by pool).

Unified /trading/amm/* carry positionAddress (required for meteora on remove,
optional on add) and expose positions-owned; fungible-LP AMMs (raydium,
uniswap, pancakeswap) ignore positionAddress and reject positions-owned with a
clear error, since a fungible LP balance has no enumerable positions.

Shared PositionInfoSchema gains an optional positions[] (PositionDetail).
Adds unified-dispatch tests (meteora remove without positionAddress -> 400;
fungible-LP positions-owned -> 400). Updates the DAMM v2 connector doc.

typecheck/lint/build clean; 84 meteora+trading tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1YS88ZAY2rXVLmgvyN4oY
@fengtality

Copy link
Copy Markdown
Contributor Author

@greptile-apps

@greptile-apps

greptile-apps Bot commented Aug 5, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a Meteora DAMM v2 connector with swap, pool, and NFT-position liquidity operations, and extends the unified AMM interface to expose pool creation and owned-position discovery.

  • Integrates @meteora-ag/cp-amm-sdk for DAMM v2 quoting and transaction construction.
  • Adds direct and unified Meteora AMM routes for swaps, liquidity, pool creation, and position discovery.
  • Extends shared schemas and connector dispatchers for pool-creation and position-addressed operations.
  • Adds documentation and unit coverage for the new connector behavior.

Confidence Score: 4/5

The automatic pool-pricing path should be fixed before merging because a price-impacting seed amount can create a new pool at an immediately arbitrageable price.

The explicit-price and explicit-quote-amount paths remain coherent, but the default path uses the full seed trade’s average execution price—including price impact and routing costs—as the pool’s initial market price.

Files Needing Attention: src/connectors/meteora/amm-routes/createPool.ts

Important Files Changed

Filename Overview
src/connectors/meteora/amm-routes/createPool.ts Implements config-driven pool creation and automatic pricing, but the fallback seeds from a size-dependent execution price that can open the pool off-market.
src/connectors/meteora/amm-routes/quoteSwap.ts Adds exact-in and exact-out DAMM v2 quote construction with token ordering and SDK-derived amounts.
src/connectors/meteora/amm-routes/executeSwap.ts Builds and submits DAMM v2 SELL and BUY transactions from the corresponding quote parameters.
src/connectors/meteora/amm-routes/addLiquidity.ts Supports adding to an explicitly owned position or creating a new NFT position with an additional signer.
src/connectors/meteora/amm-routes/removeLiquidity.ts Requires an owned position, accounts for vesting and activation time, and removes its requested unlocked-liquidity percentage.
src/trading/trading-amm-routes/create-pool.ts Extends the unified AMM route and forwards Meteora-specific pool-creation inputs without dropping fields.
src/trading/trading-amm-routes/remove-liquidity.ts Adds optional position addressing while retaining existing connector signatures and explicitly requiring it for Meteora.
src/connectors/meteora/meteora-damm.ts Introduces shared DAMM v2 pool, token-program, ownership, and activation-clock helpers.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Create-pool request] --> B{Price supplied?}
  B -->|initialPrice| C[Use explicit price]
  B -->|quoteTokenAmount| D[Derive seed ratio]
  B -->|Neither| E[Quote full baseTokenAmount through unified swap router]
  E --> F[Use average execution amountOut / amountIn]
  C --> G[Scale token amounts]
  D --> G
  F --> G
  G --> H[Prepare DAMM v2 pool parameters]
  H --> I[Create and seed pool]
Loading

Reviews (1): Last reviewed commit: "feat(meteora): position-addressed DAMM v..." | Re-trigger Greptile

`No market route found for ${baseToken}/${quoteToken}. Pass initialPrice or quoteTokenAmount explicitly.`,
);
}
return quote.amountOut / quote.amountIn; // quote token per base token

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Full-seed quote skews initial price

When the seed amount has material price impact, this ratio uses the average execution price for selling the entire baseTokenAmount, including routing fees and price impact, rather than a marginal market price. The derived quote deposit therefore opens the pool off-market and exposes its initial liquidity to immediate arbitrage.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

…e impact into pool seed price

Quoting the full seed amount returned the average execution price of that
trade (impact + routing fees included), opening the pool below market for
large seeds. Probe with a small fraction instead to approximate the
marginal price.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown

Too many files changed for review (117 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Under Review

Development

Successfully merging this pull request may close these issues.

2 participants