Repository navigation
feat(scenarios): repair Raydium AMM v4 and add Raydium CLMM templates - #21
92Infinitus92 wants to merge 11 commits into
Conversation
ff84d74 to
d41bc68
Compare
| "templateId": "raydium-clmm-pool-state", | ||
| "address": "3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv", |
There was a problem hiding this comment.
CLMM examples omit account fields The pool example uses
address, and the fee-tier example supplies no account address. Neither can be submitted as an OverrideInstance: that contract requires account in pubkey or PDA form. Show the complete account field in both examples so readers can use them in a scenario.
Knowledge Base Used:
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/core/src/scenarios/protocols/raydium/v3/README.md
Line: 80-81
Comment:
**CLMM examples omit account fields** The pool example uses `address`, and the fee-tier example supplies no account address. Neither can be submitted as an `OverrideInstance`: that contract requires `account` in pubkey or PDA form. Show the complete account field in both examples so readers can use them in a scenario.
**Knowledge Base Used:**
- [Scenario execution](https://app.greptile.com/limechain/-/custom-context/knowledge-base/limechain/surfpool/-/docs/scenario-execution.md)
- [Shared data contracts](https://app.greptile.com/limechain/-/custom-context/knowledge-base/limechain/surfpool/-/docs/shared-data-contracts.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| array, `start_index = floor(tick / (tick_spacing * 60)) * tick_spacing * 60`. A move that | ||
| stays inside the array covering the current tick is always safe; a larger move needs the | ||
| destination array to exist (`getAccountInfo` on the PDA returns null when it does not, and | ||
| the swap would fail). The Studio Raydium card computes this for you. |
There was a problem hiding this comment.
Studio card is unavailable The price-shock instructions say a Studio Raydium card computes the price, tick, and tick-array values. The current Studio scenario components provide a PumpSwap price-shock dialog, not a Raydium one. Readers must calculate these values themselves; remove the claim until that card is available, or provide a manual procedure.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/core/src/scenarios/protocols/raydium/v3/README.md
Line: 118
Comment:
**Studio card is unavailable** The price-shock instructions say a Studio Raydium card computes the price, tick, and tick-array values. The current [Studio scenario components](https://github.com/limechain/surfpool-web-ui/blob/HEAD/apps/studio/src/components/svm/scenarios-bento.tsx) provide a PumpSwap price-shock dialog, not a Raydium one. Readers must calculate these values themselves; remove the claim until that card is available, or provide a manual procedure.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.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!
Tests could not run: the pinned toolchain required a prohibited filesystem write; the installed toolchain lacked cached dependencies for offline execution. |
Tests could not run: Rustup attempted to write to a read-only directory while initializing the pinned toolchain. |
No additional concrete bugs found in the resolver/template changes. Tests could not run because Rustup attempted to write to a read-only directory. |
…iquidity rule to the custom CLMM template
a9eba96 to
691c199
Compare
There was a problem hiding this comment.
Summary
This PR fixes the Raydium AMM v4 templates. The bundled IDL now declares discriminator: [], and the resolver matches undiscriminated types by exact size. It also adds CLMM templates (pool-state, amm-config, custom), adds a collection-level llm_context, and expands the call_surfnet_rpc param docs.
The core change in resolve_idl_account_for_data looks correct:
- The longest discriminator wins.
- Undiscriminated types are tried only when no discriminated type matches, and they must fill the account exactly.
- Same-size undiscriminated types are rejected as ambiguous.
- Short data no longer panics (the old encoding path sliced
data[..8]without a length check).
I checked the documented offsets against the program layouts and they are right:
- CLMM: 73/105/137,
amm_config@9, status bits. - v4: 336/368/400/432, fees @128.
- CPMM: 168/200/72,
amm_config@8, dataSize 637.
The status enums and bitmasks also match the programs.
Scope and description
- The diff also adds Raydium CPMM templates (
raydium-cpmm-pool-state,raydium-cpmm-amm-config, a new IDL and live tests). It also swaps CI to a Claude review workflow (.github/workflows/claude-review.yml) and changes the MCPcall_surfnet_rpcschema text. The PR title and body mention none of these. Please update the description, or split them out, so reviewers know they are included. - In the review workflow, the PR body is interpolated straight into the prompt. Fork PRs are skipped and tools are read-only, so the blast radius is small, but it is a prompt-injection surface worth being aware of.
Minor
- In mixed IDLs, a discriminated type that matches by prefix but fails to decode stops the undiscriminated fallback from running. No bundled IDL mixes the two kinds today, and the new test enforces that, so this is only worth a comment in the code.
- The undiscriminated path decodes the account body twice: once in the resolver, then again in
get_forged_idl_type_data.
Overall the change is solid. The comments below are mostly about the docs and LLM guidance leaning on a Studio card that may not exist yet.
| PRICE: sqrt_price_x64 = sqrt(price_raw) x 2^64, where price_raw is token_1 per token_0 in raw units, | ||
| and tick_current = floor(log(price_raw) / log(1.0001)); set both together. A price move must also | ||
| set liquidity to the active liquidity at the new tick, and the tick array covering the new tick must | ||
| exist. The Studio price shock computes all three; prefer it to hand-computed values. |
There was a problem hiding this comment.
This collection-level llm_context reaches MCP and LLM clients, which can't use the Studio price shock. The card is also still in an open PR (surfpool-web-ui#19). Telling the model to "prefer it to hand-computed values" gives it nowhere to go, so it will likely set sqrt_price_x64/tick_current and skip liquidity.
Suggest replacing this with the manual procedure the README already documents:
- Cross ticks and add or subtract
liquidity_net. - Keep the move within the current tick array, otherwise refuse it.
The same applies to the CPMM collection context ("the Studio price shock writes both vaults").
|
|
||
| ## Shock the price | ||
|
|
||
| Use **Scenario presets → Raydium state → CLMM price shock** in Studio. It reads the pool and the |
There was a problem hiding this comment.
This recipe points readers to Scenario presets → Raydium state → CLMM price shock, but that depends on surfpool-web-ui#19, which hasn't landed. Please either gate the wording ("once available") or spell out the manual steps first: read the tick arrays, sum liquidity_net across the crossed ticks, and check that the destination array PDA exists. The troubleshooting row at line 90 has the same dependency.
| .into_iter() | ||
| .filter(|account| data.starts_with(&account.discriminator)) | ||
| .collect(); | ||
| if candidates.is_empty() { |
There was a problem hiding this comment.
The undiscriminated fallback runs only when no discriminated type matches by prefix. In a mixed IDL, a discriminated type can match by prefix and then fail to decode. When that happens, the matching undiscriminated type is never tried, and the forge fails with a decode error instead of resolving.
No bundled IDL mixes the two today, and the registry test enforces that. Still, please add a short comment stating the assumption, or only drop the undiscriminated candidates when a discriminated one actually decodes.
| )) | ||
| })?; | ||
| // Find the account type, then split its discriminator off the data | ||
| let account_def = resolve_idl_account_for_data(idl, account_data).map_err(|reason| { |
There was a problem hiding this comment.
For undiscriminated accounts, the resolver already decoded the whole body to check that it fills the account exactly. get_forged_idl_type_data then decodes it again. That's cheap at 752 bytes, but TargetOrders is ~2.2 KB with nested arrays. Consider having the resolver return the parsed Value so the forge path can reuse it.
Repairs the Raydium AMM v4 templates and adds Raydium CLMM (amm_v3) state prep.
AMM v4 stores no discriminator, so the bundled IDL used to carry made-up ones and no
override ever matched a real pool. The IDL now declares
discriminator: []forAmmInfoand
TargetOrders, and the forge resolver matches such types by exact body size when nodiscriminated type claims the account. Data shorter than every discriminator, or with
leftover bytes, fails with the usual "no account type" error. The hard-coded market list
and the script that generated it are gone; templates take a pool address.
Templates:
raydium-amm-pool-state,raydium-amm-fees,raydium-amm-swap-statsraydium-clmm-pool-state,raydium-clmm-amm-config(fee tier by config index,address derived),
raydium-clmm-customYAML and IDL only, like Kamino: no protocol Rust and no MCP tool. The price/tick coupling,
the tick array PDA recipe and the "stay inside the current tick array" rule live in the
pool-state template's
llm_contextand in the README; the Studio card computes the shockclient-side (LimeChain/surfpool-web-ui#19).
Tests: resolver unit tests for the exact-fill, same-size ambiguity and longer-discriminator
cases; live tests (
--features integration-tests) round-trip real mainnet pools byte forbyte and apply overrides through the materializer, asserting only the targeted bytes
change. Verified on a forked surfnet: a 0.5 shock on the SOL/USDC pool made a real swap
fill at half the mainnet quote, and status 3 on the v4 pool made the program reject swaps.
The PR appears safe to merge, with non-blocking CLMM documentation corrections recommended.
Fix with agent prompt
Summary
The PR makes Raydium AMM v4 accounts resolvable without invented discriminators, replaces the v4 market-derived template with pool-address templates, and adds CLMM pool and fee-tier templates. The principal follow-ups are to make the CLMM examples valid scenario instances and align the price-shock documentation with the available Studio UI.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR T[Raydium template and instance] --> A[Resolve pool address or config PDA] A --> F[Fetch or read local account] F --> R[Resolve IDL account type] R --> O[Apply field overrides] O --> S[Updated local account]Reviews (1) · Last reviewed commit: "feat(scenarios): repair Raydium AMM v4 a..."