MBCOiso-xmmMAINNET

Integrate

no SDK2 enginesRPC-only

Wire both iso engines from any aggregator (cq1, cq2, cqV, dflow, titan, jupiter, etc). All ix bodies are little-endian; only PDA index seeds are big-endian. Decode pool, quote, build ix.

skill.md for AI agentscopy + paste

One copyable, self-contained spec. Paste it into Claude Code, Cursor, or any coding agent to wire iso-xmm with no SDK. Sourced 1:1 from the live TS client + IDL.

IDL JSONprogram isogrR..qSZK2 engines1-byte disc
# iso-xmm integration skill (paste into any AI coding agent)

A self-contained spec to integrate iso-xmm, a Solana AMM with two live engines (Apex
CLMM + Pulse oracle-anchored maker). No SDK needed: decode the pool, quote, build the
1-byte-discriminator swap instruction, sign, send. Sourced from the live TS client and IDL.

Conventions, fixed:
- Each iso account carries a 1-BYTE discriminator at byte 0 (not Anchor's 8-byte hash).
- Instruction data: byte 0 is the 1-byte ix discriminator; all body scalars LITTLE-endian.
- PDA seeds: every index-bearing seed is BIG-endian (i32/u16 to_be_bytes); the pool
  nonce tail is u32 LITTLE-endian. Account-DATA scalars are LITTLE-endian.
- u128 in account data = two LE u64 halves, low 8 bytes then high 8 bytes.

## Address book (mainnet)
program     isogrRJ6sEiktnfUY7QdZhDr5Sut3C8ER9HejjUqSZK
amm_config  Eousgm9tP3EjdheeB3MKfFU4zvZtxD6cnpY8FijbkG4M
Apex  pool  isoJANGQx1GmbmLUbGDa34Qxe6GLppFNxrZw5Kx5fX9   (CLMM, SOL/USDC, account disc 2)
Pulse pool  isoLWsMtAQT58VzufDJEiXGFV6PjiamtLwseHe6hBVw   (anchored, SOL/SPDR, account disc 7)
mpl-core    CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d   (position NFT)
SPL Token   TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Token-2022  TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
IDL (Codama, 1-byte discriminators): https://xmm.mbco.io/xmm.json

Mints: SOL So11111111111111111111111111111111111111112 (9), USDC
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v (6), SPDR
AT79ReYU9XtHUTF5vM6Q4oa9K8w7918Fp5SU7G1MDMQY (9).

## Apex (CLMM) swap, ix disc 6
data (34 bytes):
[0]      u8    disc = 6
[1..9]   u64   amount                 (LE)
[9..17]  u64   other_amount_threshold (LE)   // exact-in -> min out
[17..33] u128  sqrt_price_limit_x64   (LE)    // 0 = no limit
[33]     u8    is_base_input          (1/0)

accounts (10 head, then ordered tail):
0   payer                 signer, writable
1   amm_config            readonly
2   pool                  writable
3   user_in  (ATA)        writable
4   user_out (ATA)        writable
5   input_vault           writable
6   output_vault          writable
7   observation           writable
8   input_token_program   readonly   // must own the INPUT vault (SPL vs Token-2022)
9   output_token_program  readonly   // must own the OUTPUT vault
-- tail --
10  bitmap_ext            writable    // FIRST in tail
11+ tick_array[]          writable    // direction-ordered window

Direction is inferred on-chain from the input vault. zero_for_one = input is mint_0
(price falls); one_for_zero = input is mint_1 (price rises). Vaults: zero_for_one ->
input=vault0, output=vault1; else swapped. Tick-array window: start at the array holding
tick_current, walk the swap direction (DOWN for zero_for_one, UP otherwise), step =
tick_spacing * 60; include only on-chain-initialized neighbors (account disc 3), pad to
>=2 with the current array (an uninitialized neighbor reverts 6002). Cap 12 arrays.

## Pulse (anchored) swap, ix disc 18 (swap_anchor)
data (17 bytes):
[0]      u8    disc = 18
[1..9]   u64   amount                 (LE)
[9..17]  u64   other_amount_threshold (LE)   // min out

accounts (8, no tail):
0  payer                 signer, writable
1  pool                  readonly
2  user_in  (ATA)        writable
3  user_out (ATA)        writable
4  input_vault           writable
5  output_vault          writable
6  input_token_program   readonly
7  output_token_program  readonly
No tick arrays, no bitmap, no observation: the maker posts the mid; fill is at
posted-mid +/- band, zero curve slippage.

## PDA seeds (program id isogrRJ6sEiktnfUY7QdZhDr5Sut3C8ER9HejjUqSZK)
amm_config   "amm_config", index                                  index = u16 BE
pool (Apex)  "pool", amm_config, mint0, mint1, nonce              nonce = u32 LE
pool (Pulse) "pool_anchor", amm_config, mint0, mint1, nonce       nonce = u32 LE
vault        "pool_vault", pool, mint                             none
observation  "observation", pool                                  none
bitmap_ext   "pool_tick_array_bitmap_extension", pool             none
tick_array   "tick_array", pool, start_tick_index                 start = i32 BE
position     "position", core_asset                               none (NFT mint)
mint_0 addr < mint_1 addr. tick_array start = floor-toward-negative-infinity of
tick_current over (tick_spacing * 60) ticks/array. ATA = [owner, tokenProgram, mint].

## Pool decode offsets
PoolClmm (disc 2, 1545 B):
2 amm_config pubkey | 66 token_mint0 | 98 token_mint1 | 130 token_vault0 |
162 token_vault1 | 194 observation | 226 mint_decimals0 u8 | 227 mint_decimals1 u8 |
228 tick_spacing u16 | 230 liquidity u128 | 246 sqrt_price_x64 u128 | 262 tick_current i32 |
382 status u8 (bit0=halt) | 1089 fee_rate u32 (bp = fee_rate/100000; 10000 -> 0.1 bp) |
1093 pool_nonce u32
PoolAnchor (disc 7):
72 token_mint0 | 104 token_mint1 | 136 token_vault0 | 168 token_vault1 |
200 pricer_hot_key | 232 mint_decimals0 u8 | 233 mint_decimals1 u8 | 234 status u8 |
235 haircut_bps_p1 u8 | 236 round_mode u8 | 240 price_x64 u128 | 256 bid_factor u64 |
264 ask_factor u64 | 272 confidence u64 | 280 price_updated_ms u64 | 304 capacity_cap u64

## Quote
Apex (CLMM) spot:
  price     = (sqrt_price_x64 / 2^64)^2 * 10^(dec0 - dec1)   // quote per base, human
  feeFactor = 1 - fee_rate / 1e9
  zeroForOne = inputMint == token_mint0
  out       = zeroForOne ? amountIn * price * feeFactor : (amountIn / price) * feeFactor
  minOut    = floor(out * (1 - slippage))
  // constant-price at current sqrt_price; walk tick arrays for size. tick->price = 1.0001^tick * 10^(dec0-dec1)
Pulse (anchored):  // exact integer replay; see lib/xmm/router.ts anchorQuoteOut
  inputIsBase = inputMint == token_mint0
  band = (inputIsBase ? bid_factor : ask_factor) || 1e12   // maker side, 1e12-scaled (0=flat)
  eff  = price_x64 * band / 1e12                            // Q64.64 effective price
  haircut_bps = data[235]==0 ? 5 : min(data[235]-1, 5)      // SENTINEL @235
  // round_mode SENTINEL @236: 1 = PRECISE (fold the 10^|dec| rescale into ONE floor-divide,
  // no up-rescale truncation); else LEGACY (floor the price divide, THEN rescale). isoZbS=1.
  PRECISE base->quote: out = (amountIn*eff*10^max(d1-d0,0)) / (2^64 *10^max(d0-d1,0))  // floor once
  PRECISE quote->base: out = (amountIn*2^64*10^max(d0-d1,0)) / (eff  *10^max(d1-d0,0)) // floor once
  out = floor(out) * (10000 - haircut_bps) / 10000   // quote 0 if halted (status bit0) or stale

## Enumerate / stream
memcmp the 1-byte disc at offset 0. Single-byte disc base58 = one char: disc 2 -> "3",
disc 7 -> "8", position disc 4 -> "5".
  getProgramAccounts(programId, { filters: [{ memcmp: { offset: 0, bytes: "3" } }] })  // every Apex pool
  getAccountInfo(pool, "base64"); require owner == programId && data[0] == 2 (or 7)
Yellowstone gRPC: subscribe accounts owned by the program; add { memcmp: { offset: "0",
base58: "3" } } to scope one engine. Decode bytes the same way as getAccountInfo.

## Build + send
1. getAccountInfo(pool); require owner == program and data[0] == 2 (Apex) or 7 (Pulse).
2. Decode at the offsets above; quote with the engine formula.
3. Resolve user_in/user_out ATAs; resolve each token program from the mint owner (both
   legs SPL for the live pools). SOL leg: wrap via System transfer + SPL sync_native
   (byte 17); unwrap after via SPL close_account (byte 9).
4. Build swap ix: data = [disc] + LE body; accounts in the order above. Apex tail =
   bitmap_ext FIRST, then the direction-ordered tick-array window.
5. Sign + sendTransaction. Reference CU: Apex ~27,959; Pulse ~10,000.

Address book (mainnet)

Lightcore runtime, 1-byte discriminator dispatch. First-party on-chain TWAP oracle, no external feed.

WhatAddressNote
programisogrR..qSZKowner of all iso accounts
amm_configEousgm..kG4Mfee tier, shared by both engines
Apex SOL/USDCisoJAN..5fX9CLMM, disc 2
Pulse SOL/SPDRisoLWs..hBVwanchored, disc 7
mpl-coreCoREEN..hX7dposition NFT (range + fees)
fee 0.1 bp (10000 / 1e9)1/10 cheapest Solana AMMpermissionlessStrata bins = ROADMAP

Engine matrix

Two live engines. Pick by the pool account discriminator at byte 0.

FieldApex (CLMM)Pulse (anchored)
modelconcentrated liquidityoracle-anchored maker, zero curve slippage
pool disc27
swap ix disc6 · swap18 · swap
ix bodyu64 amount, u64 thr, u128 sqrtLimit, u8 baseIn (34B)u64 amount, u64 thr (17B)
accounts10 head + bitmap + tick arrays8
quote(sqrtP/2^64)^2 * 10^(d0-d1)priceX64/2^64, then ± band
fee0.1 bpzero fee, maker earns the spread
swap CU~27,959~10,000

Reference: closed prop AMMs are ~95,000 CU for a swap. open_position 44,229 / add_liquidity 25,920 / create_pool 38,949 / post_price 680 CU.

Swap instruction layout

data[0] = 1-byte disc. Body scalars LITTLE-endian. inputTokenProgram / outputTokenProgram must match the vault owners (SPL vs Token-2022).

Apex swapdisc 6
data (34 bytes)
[0]      u8   disc = 6
[1..9]   u64  amount            (LE)
[9..17]  u64  otherAmtThreshold (LE)  // min out / max in
[17..33] u128 sqrtPriceLimitX64 (LE)  // 0 = no limit
[33]     u8   isBaseInput       (1/0)

accounts (10 head, then tail)
0  payer            signer, w
1  amm_config       ro
2  pool             w
3  user_in (ATA)    w
4  user_out (ATA)   w
5  input_vault      w
6  output_vault     w
7  observation      w
8  input_token_prog ro   // routes input vault
9  output_token_prog ro  // routes output vault
-- tail --
10 bitmap_ext       w    // FIRST in tail
11.. tick_array[]    w    // window, ordered
Pulse swapdisc 18 · swap_anchor
data (17 bytes)
[0]      u8   disc = 18
[1..9]   u64  amount            (LE)
[9..17]  u64  otherAmtThreshold (LE)  // min out / max in

accounts (8)
0 payer             signer, w
1 pool              ro
2 user_in (ATA)     w
3 user_out (ATA)    w
4 input_vault       w
5 output_vault      w
6 input_token_prog  ro   // routes input vault
7 output_token_prog ro   // routes output vault

// no tick arrays, no bitmap, no observation:
// the maker posts the mid, fill is at posted-mid ± band.

Direction is inferred on-chain from the input vault. zero_for_one = input is mint_0 (price falls); one_for_zero = input is mint_1 (price rises). The Apex tick-array window starts at tick_current's array and walks the swap direction (down for zero_for_one), max 12 arrays.

PDA derivation

Every index-bearing seed is BIG-endian (to_be_bytes); the pool nonce tail is u32 LITTLE-endian. Account-data scalars are LE.

AccountSeedsEncoding
amm_config"amm_config", indexindex = u16 BE
pool (Apex)"pool", amm_config, mint0, mint1, noncenonce = u32 LE
pool (Pulse)"pool_anchor", amm_config, mint0, mint1, noncenonce = u32 LE
vault"pool_vault", pool, mintnone
observation"observation", poolnone
bitmap_ext"pool_tick_array_bitmap_extension", poolnone
tick_array"tick_array", pool, start_tick_indexstart = i32 BE
position"position", core_assetnone (NFT mint)

mint_0 addr < mint_1 addr. tick_array start = floor-toward-negative-infinity over tick_spacing × 60 ticks per array.

Pool decode offsets

Fixed-offset decoders. u128 is two LE u64 halves (lo then hi). disc at byte 0.

PoolClmm (disc 2)
2    amm_config     pubkey
66   token_mint0    pubkey
98   token_mint1    pubkey
130  token_vault0   pubkey
162  token_vault1   pubkey
194  observation    pubkey
226  mint_decimals0 u8
227  mint_decimals1 u8
228  tick_spacing   u16
230  liquidity      u128
246  sqrt_price_x64 u128
262  tick_current   i32
382  status         u8   (bit0 = halt)
1089 fee_rate       u32  (/1e5 = bp)
1093 pool_nonce     u32
PoolAnchor (disc 7)
72   token_mint0    pubkey
104  token_mint1    pubkey
136  token_vault0   pubkey
168  token_vault1   pubkey
200  pricer_hot_key pubkey
232  mint_decimals0 u8
233  mint_decimals1 u8
234  status         u8
235  haircut_bps_p1 u8   (SENTINEL: 0=>5bp; v>=1=>min(v-1,5) bp)
236  round_mode     u8   (SENTINEL: 1=precise rounding, else legacy)
240  price_x64      u128
256  bid_factor     u64
264  ask_factor     u64  (band = (f/1e12-1)*1e4 bp)
272  confidence     u64
280  price_updated_ms u64
304  capacity_cap   u64

Integrate a swap in 3 steps · Apex

Apex (CLMM): walk ticks at the current sqrt_price.

1. DECODE POOL
   getAccountInfo(pool); require owner == program && data[0] == 2
   read sqrt_price_x64@246, tick_current@262, tick_spacing@228,
        decimals@226/227, fee_rate@1089, vaults@130/162

2. QUOTE  (spot, refine by walking ticks for size)
   price = (sqrt_price_x64 / 2^64)^2 * 10^(dec0 - dec1)   // quote per base
   feeFactor = 1 - fee_rate / 1e9
   zeroForOne = inputMint == token_mint0
   out = zeroForOne ? amountIn * price * feeFactor
                    : (amountIn / price) * feeFactor
   minOut = floor(out * (1 - slippage))

3. BUILD + SEND  (ix disc 6)
   input/output vault by direction (zeroForOne -> vault0/vault1)
   tickArrays = window from arrayStart(tick_current) walking direction
   data = [6] u64(amountIn) u64(minOut) u128(0) u8(1)   // baseIn, no limit
   accounts: 10 head + bitmap_ext + tickArrays  (table above)
   sign + sendTransaction

Integrate a swap in 3 steps · Pulse

Pulse (anchored): posted-mid fill, no curve, no tick arrays.

1. DECODE POOL
   getAccountInfo(pool); require owner == program && data[0] == 7
   read price_x64@240, bid_factor@256, ask_factor@264, decimals@232/233,
        status@234 (tradable when bit0 clear), haircut_bps_p1@235,
        round_mode@236, vaults@136/168

2. QUOTE  (posted mid +/- band, zero curve slippage; integer, see router.ts)
   inputIsBase = inputMint == token_mint0
   band = (inputIsBase ? bid_factor : ask_factor) || 1e12   // maker side (0=flat)
   eff  = price_x64 * band / 1e12
   haircut_bps = data[235]==0 ? 5 : min(data[235]-1, 5)     // SENTINEL @235
   // round_mode @236: 1=PRECISE (fold 10^|dec| into ONE floor-divide), else LEGACY.
   PRECISE base->quote: out = (amountIn*eff*10^max(d1-d0,0)) / (2^64*10^max(d0-d1,0))
   PRECISE quote->base: out = (amountIn*2^64*10^max(d0-d1,0)) / (eff*10^max(d1-d0,0))
   out = floor(out) * (10000 - haircut_bps) / 10000        // 0 if halted/stale

3. BUILD + SEND  (ix disc 18)
   input/output vault by direction
   data = [18] u64(amountIn) u64(minOut)
   accounts: 8 (payer, pool, user_in, user_out,
               input_vault, output_vault, in_tprog, out_tprog)
   sign + sendTransaction

Read pools (RPC + gRPC)

Enumerate, snapshot, and stream every iso pool/position off-chain. memcmp the 1-byte disc at offset 0; single-byte disc base58 is one char (bs58Disc, e.g. disc 2 -> "3").

Accountdiscmemcmp byte (base58)
Apex pool2"3"
Pulse pool7"8"
position4"5"
JSON-RPCenumerate one engine
// every Apex (CLMM) pool: getProgramAccounts + memcmp disc 2 -> "3"
// Pulse pools -> disc 7 -> "8"; positions -> disc 4 -> "5"
curl $RPC -s -d '{
  "jsonrpc":"2.0","id":1,"method":"getProgramAccounts",
  "params":["isogrRJ6sEiktnfUY7QdZhDr5Sut3C8ER9HejjUqSZK",{
    "encoding":"base64",
    "filters":[{"memcmp":{"offset":0,"bytes":"3"}}]
  }]
}'
// -> [{ pubkey, account:{ owner, data:[<base64>,"base64"] }}, ...]
JSON-RPCsnapshot one pool
// one known pool -> base64 -> decode at the offsets above
curl $RPC -s -d '{
  "jsonrpc":"2.0","id":1,"method":"getAccountInfo",
  "params":["isoJANGQx1GmbmLUbGDa34Qxe6GLppFNxrZw5Kx5fX9",
            {"encoding":"base64"}]
}'
// d = base64-decode(data[0]); require d[0] == 2 (Apex)
//   sqrt_price_x64 = u128 LE @246  tick_current = i32 LE @262
//   liquidity      = u128 LE @230
// Pulse pool isoLWsMtAQT58VzufDJEiXGFV6PjiamtLwseHe6hBVw, d[0] == 7:
//   price_x64 = u128 LE @240  ask_factor = u64 LE @264 (band)
Yellowstone gRPCstream every change
// Geyser push updates: filter accounts owned by the program. Add the
// disc memcmp to scope one engine. Endpoint is integrator-configured.
import Client from "@triton-one/yellowstone-grpc";

const client = new Client(GRPC_ENDPOINT, GRPC_TOKEN, undefined);
const stream = await client.subscribe();
stream.write({
  accounts: {
    iso: {
      owner: ["isogrRJ6sEiktnfUY7QdZhDr5Sut3C8ER9HejjUqSZK"],
      account: [],
      // optional: one engine only (Apex). drop to stream all accounts.
      filters: [{ memcmp: { offset: "0", base58: "3" } }],
    },
  },
  slots: {}, transactions: {}, blocks: {}, blocksMeta: {}, entry: {},
  accountsDataSlice: [], commitment: 1, // CONFIRMED
});
// each msg.account.account = { pubkey, owner, data(bytes), ... }
// decode data the same way as getAccountInfo above (disc @0).

These are the exact reads the iso TS client performs (ui/src/lib/xmm: getProgramAccounts + memcmp in pools.ts, decodePoolClmm / decodePoolAnchor in state.ts).

Public REST APIopenrate limited

Open, no key, read-only (GET). Base /api/v1. CORS Access-Control-Allow-Origin: *. Per-IP token bucket, 60 req/min; every response carries X-RateLimit-Limit/Remaining/Reset, a 429 adds Retry-After. The reads are the iso TS client (listLivePools / loadPoolRow / quoteClmm) over RPC.

EndpointReturns
GET /api/v1/poolsall live pools (engine, pair, price, fee, tvl, reserves, addresses)
GET /api/v1/pools/{id}one pool (either engine); 404 if not an iso pool
GET /api/v1/quote?pool=&in=&amount=Apex (CLMM) spot quote: out, price, feeBps, minReceived hint
GET /api/v1/oraclefirst-party multi-source price oracle (baselines, pairs, freshness)
GET /api/v1/infoprogram id, pools, amm_config, IDL url, engines, version
CORS *60 req/min/IPX-RateLimit-Limit/Remaining/Reset429 + Retry-After
# iso-xmm public REST API   base: https://xmm.mbco.io/api/v1
# Open, no key. CORS: Access-Control-Allow-Origin: *. Read-only (GET).
# Rate limit: 60 req/min per IP (token bucket). Every response sets:
#   X-RateLimit-Limit: 60
#   X-RateLimit-Remaining: <n>
#   X-RateLimit-Reset: <unix-seconds when the bucket is full>
# Over the limit -> HTTP 429 { "error": "rate limit exceeded", "retryAfter": <s> }
#   + Retry-After: <seconds>

## GET /api/v1/pools            all live pools
curl -s https://xmm.mbco.io/api/v1/pools
# -> { count, pools: [ { name, id, engine, pair, price, feeBps, tvl, status,
#      reserves:{base,quote}, addresses:{pool,ammConfig,baseMint,quoteMint,
#      vault0,vault1,observation}, decimals:{base,quote}, tickCurrent, tickSpacing,
#      liquidity, bandBps, confidence, priceUpdatedMs } ] }

## GET /api/v1/pools/{id}       one pool (either engine); 404 if not an iso pool
curl -s https://xmm.mbco.io/api/v1/pools/isoJANGQx1GmbmLUbGDa34Qxe6GLppFNxrZw5Kx5fX9
# -> the single pool object (same shape as an element of /pools)
# 404 -> { "error": "not an iso pool", "id": "<addr>" }

## GET /api/v1/quote            Apex (CLMM) spot quote
#   pool         iso CLMM pool address (clmm only; 400 for an anchored pool)
#   in           input token: symbol (SOL/USDC) OR mint address
#   amount       input amount, human units of `in`
#   slippageBps  optional, default 50 (0.5%) -> drives minReceived
curl -s 'https://xmm.mbco.io/api/v1/quote?pool=isoJANGQx1GmbmLUbGDa34Qxe6GLppFNxrZw5Kx5fX9&in=SOL&amount=1.5'
# -> { pool, engine, in:{token,amount}, out:{token,amount}, price, feeBps,
#      inputIsBase, slippageBps, minReceived, note }
# minReceived = out * (1 - slippageBps/1e4); set as other_amount_threshold (raw)
# on the disc-6 swap ix (see Write operations below).

## GET /api/v1/oracle           first-party multi-source price oracle (display mirror)
curl -s https://xmm.mbco.io/api/v1/oracle
# -> { asset:"USD", baselines:{ SOL,USDC,USDT,CHF: { price, conf, dispersion,
#      median, sources:[{name,price,ageSec,kept}], fresh } },
#      pairs:[ { pair, base, quote, mid, fresh } ], staleness, ts, cachedForMs }
# Recomputes the SAME aggregation the on-chain pricer posts; ~3s server cache.

## GET /api/v1/info             program id, pools, amm_config, IDL url, engines, version
curl -s https://xmm.mbco.io/api/v1/info
# -> { name, version, build, programId, ammConfig, idlUrl, engines[], pools[], api{} }

# Errors are JSON: { "error": "<msg>", ... }. Statuses: 200 ok, 400 bad query,
# 404 not an iso pool, 429 rate limited, 502 upstream RPC error.

Write operations (pool lifecycle)build + sign1-byte disc

The REST API is read-only. To write, build + sign these instructions yourself. disc = 1-byte ix at data[0]; body scalars LITTLE-endian; PDA index seeds BIG-endian (nonce tail u32 LE). Mirrored 1:1 from program/idl/xmm.json + ui/src/lib/xmm/ix.ts.

create_pool 2create_anchor_pool 16open_position 3increase 4decrease 5collect_fees 7close_position 8close_pool 22
# iso-xmm WRITE operations (on-chain instruction recipes)
# The REST API is read-only. To WRITE, build + sign these instructions yourself.
# program isogrRJ6sEiktnfUY7QdZhDr5Sut3C8ER9HejjUqSZK
# data[0] = 1-byte ix disc; body scalars LITTLE-endian; string = u8 len + bytes.
# PDA index seeds BIG-endian; pool nonce tail u32 LE; ATA = [owner, tokenProgram, mint].
# token_program_{0,1} MUST equal the owner of mint_{0,1} (SPL vs Token-2022).
# mpl_core = CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d
# system   = 11111111111111111111111111111111

## create_pool  (disc 2)  -> PoolStateClmm + 2 vaults + observation + bitmap_ext + Core collection
body: pool_nonce u32 | sqrt_price_x64 u128 | name (u8 len + bytes) | uri (u8 len + bytes)
accounts:
 0  creator               signer, w   funds rent; Core collection signer
 1  amm_config            ro          decoded for tick_spacing/fee
 2  pool                  w           PDA ["pool", amm_config, mint0, mint1, nonce_le]
 3  token_mint_0          ro          addr(mint0) < addr(mint1)
 4  token_mint_1          ro
 5  token_vault_0         w           PDA ["pool_vault", pool, mint0]
 6  token_vault_1         w           PDA ["pool_vault", pool, mint1]
 7  observation           w           PDA ["observation", pool]
 8  bitmap_extension      w           PDA ["pool_tick_array_bitmap_extension", pool]
 9  collection            signer, w   iso-vanity client keypair (Core collection)
 10 token_program_0       ro          == owner(mint0)
 11 token_program_1       ro          == owner(mint1)
 12 mpl_core              ro
 13 system_program        ro
# sqrt_price_x64 = floor(sqrt(price_raw) * 2^64), price_raw = token1_raw/token0_raw.

## create_anchor_pool  (disc 16)  -> PoolStateAnchor + 2 vaults (Engine B)
body: pool_nonce u32 | pricer_hot_key pubkey(32) | delta_cap_bps u64 | capacity_cap u64
    | max_slot_lag u64 | max_age_ms u64 | s_floor u64 | cap_bps u64 | conf_max u64
    | [guardian: option<pubkey>] | [max_band_bps: option<u64>]
# option = 1 byte (0 = none, 1 = present) then the value. Body 92 / 124 / 132 bytes.
accounts:
 0  creator               signer, w   funds rent; pool authority (owner)
 1  amm_config            ro
 2  pool                  w           PDA ["pool_anchor", amm_config, mint0, mint1, nonce_le]
 3  token_mint_0          ro          addr(mint0) < addr(mint1)
 4  token_mint_1          ro
 5  token_vault_0         w           PDA ["pool_vault", pool, mint0]
 6  token_vault_1         w           PDA ["pool_vault", pool, mint1]
 7  token_program_0       ro          == owner(mint0)
 8  token_program_1       ro          == owner(mint1)
 9  system_program        ro
# Then disc 17 post_price (pricer_hot_key signs) seeds the first quote; disc 19
# deposit_inventory funds the vaults. SwapAnchor (disc 18) is read-side in /docs above.

## open_position  (disc 3)  -> PositionState PDA + Core NFT, liquidity starts 0
body: tick_lower_index i32 | tick_upper_index i32     (lower < upper, on tick_spacing)
accounts:
 0  payer                 signer, w   funds rent; NFT owner; rent_receiver
 1  pool                  ro          decoded for tick_spacing
 2  position              w           PDA ["position", asset]
 3  asset                 signer, w   iso-vanity client keypair (Core NFT)
 4  collection            w           the pool's Core collection
 5  tick_array_lower      w           PDA ["tick_array", pool, lower_start_be]
 6  tick_array_upper      w           PDA ["tick_array", pool, upper_start_be]
 7  mpl_core              ro
 8  system_program        ro
# *_start = floor-to-neg-inf of the boundary tick over (tick_spacing * 60) ticks.

## increase_liquidity  (disc 4)  -> deposit (amounts round UP)
body: amount_0_max u64 | amount_1_max u64
accounts:
 0  owner                 signer      gated by asset ownership
 1  pool                  w
 2  position              w           PDA ["position", asset]
 3  asset                 ro          Core NFT (ownership gate)
 4  tick_array_lower      w
 5  tick_array_upper      w
 6  token_owner_0         w           user src ATA (mint0)
 7  token_owner_1         w           user src ATA (mint1)
 8  token_vault_0         w           == pool.token_vault_0
 9  token_vault_1         w           == pool.token_vault_1
 10 token_program_0       ro
 11 token_program_1       ro
 12 bitmap_extension      w  OPTIONAL  ["pool_tick_array_bitmap_extension", pool]
# bitmap_extension only when a boundary array is outside the pool-internal window.

## decrease_liquidity  (disc 5)  -> withdraw (amounts round DOWN; pool PDA signs vault-out)
body: liquidity u128 | amount_0_min u64 | amount_1_min u64
accounts: same 13 as increase_liquidity (idx 12 bitmap_extension OPTIONAL),
          token_owner_{0,1} are the user DST ATAs here.

## collect_fees  (disc 7)  -> pay owed fees to the owner, re-snapshot fee_growth_inside
body: (none)
accounts:
 0  owner                 signer      ownership gate
 1  pool                  ro          fee_growth source; PDA signs vault-out
 2  position              w           PDA ["position", asset]
 3  asset                 ro          Core NFT
 4  token_owner_0         w           user dst ATA (mint0)
 5  token_owner_1         w           user dst ATA (mint1)
 6  token_vault_0         w
 7  token_vault_1         w
 8  token_program_0       ro
 9  token_program_1       ro
 10 tick_array_lower      ro          fee_growth_outside source
 11 tick_array_upper      ro

## close_position  (disc 8)  -> burn the Core NFT, reclaim rent (liquidity==0 AND owed==0)
body: (none)
accounts:
 0  owner                 signer, w   ownership gate; BurnV1 authority
 1  position              w           PDA ["position", asset]
 2  asset                 w           Core NFT to burn
 3  collection            w           the pool's Core collection
 4  rent_receiver         w           == position.rent_receiver
 5  mpl_core              ro
 6  system_program        ro

## close_pool  (disc 22)  -> owner teardown of an EMPTY + PAUSED pool (set_status first)
body: (none)
accounts (CLMM, 11):
 0  authority             signer      == pool.owner
 1  pool                  w           PDA signs vault sweep + close
 2  observation           w  OPTIONAL CLMM only: == pool.observation_key
 3  bitmap_extension      w  OPTIONAL CLMM only
 4  vault_0               w
 5  vault_1               w
 6  dst_0                 w           owner ATA(mint0) sweep target
 7  dst_1                 w           owner ATA(mint1) sweep target
 8  rent_receiver         w
 9  token_program_0       ro
 10 token_program_1       ro
# Anchored pool: omit observation + bitmap_extension (9 accounts; rest shift down by 2).
# Pre-req: disc 21 set_status(bit, disable=1) to HALT, and the pool must be empty.

# Lifecycle order:
#   CLMM:   create_pool -> open_position -> increase_liquidity -> (swap disc 6 / collect_fees)
#           -> decrease_liquidity -> close_position -> set_status(halt) -> close_pool
#   Anchor: create_anchor_pool -> post_price (disc 17) -> deposit_inventory (disc 19)
#           -> (swap_anchor disc 18) -> withdraw_inventory (disc 20) -> set_status -> close_pool
seeds = BE index, LE nonceix body = LEu128 = lo|hi LE u64token prog must match vault ownermemcmp disc @0