Skip to content

feat(scenarios): add PancakeSwap CLMM templates - #24

Open
92Infinitus92 wants to merge 13 commits into
feat/scenarios/override/pancakeswap-supportfrom
feat/scenarios/pancakeswap
Open

92Infinitus92 wants to merge 13 commits into
feat/scenarios/override/pancakeswap-supportfrom
feat/scenarios/pancakeswap

Conversation

@92Infinitus92

@92Infinitus92 92Infinitus92 commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Adds PancakeSwap (Solana) CLMM state prep. Stacked on #21: PancakeSwap is a Raydium CLMM
fork with identical PoolState, AmmConfig and TickArrayState layouts, so the templates
mirror the Raydium CLMM ones under the PancakeSwap program id.

Heads up on the size: 1854 lines of the diff are the vendored IDL.

Templates: pancakeswap-clmm-pool-state, pancakeswap-clmm-amm-config (22 fee tiers by
config index, address derived) and pancakeswap-clmm-custom.

YAML 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_context and in the README; the Studio card computes the shock
client-side (LimeChain/surfpool-web-ui#22).

Tests: the two IDLs were compared field by field; live tests round-trip a real mainnet
pool, check every fee tier against its live AmmConfig, and apply overrides through the
materializer asserting only the targeted bytes change. Verified on a forked surfnet:
a 0.5 shock made a real swap_v2 fill at half the mainnet quote.

Known limitation (in the README): the engine picks the IDL by account owner, so a
PancakeSwap template pointed at a Raydium CLMM pool writes the same bytes.

@github-actions

Copy link
Copy Markdown
  • [P2] Custom template omits the liquidity rule — overrides.yaml:270. Its price-shock guidance only couples price and tick. Crossing initialized ticks also requires updating active liquidity; otherwise swaps can silently return incorrect amounts. Include the liquidity and tick-array guidance already present in the address-based template.

  • [P3] Worked example cannot deserialize as an override — README.md:59. Replace "address" with "account": {"pubkey": "..."} and include required id, scenarioRelativeSlot, and enabled fields so the example is usable.

Shared IDL definitions match Raydium’s exactly. Tests could not run because rustup attempted to write to a read-only directory.

@github-actions

Copy link
Copy Markdown

No confirmed bugs found in the PR changes. The three core account layouts match Raydium’s, and the new IDL discriminators are correct.

One improvement: the materializer test omits sqrt_price_x64, despite price shocks being the main use case. Include a decimal-string override above u64::MAX and assert that only bytes 253..269 change, covering the critical u128 write path.

I couldn’t run the Rust tests: rustup attempted to write to a read-only directory.

@github-actions

Copy link
Copy Markdown

No concrete bugs found in the specified PR changes.

One improvement: add an offline account fixture for the byte-level materializer test in pancakeswap/mod.rs. Currently, that coverage requires mainnet access and integration-tests, so ordinary CI misses it.

Validation: IDL layouts and discriminators checked; diff whitespace checks passed. Rust tests could not run because rustup attempted to write to a read-only directory.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

No concrete bugs found in the PR changes. The PDA definitions and PoolState/AmmConfig layouts match the existing Raydium implementation.

One improvement: add an offline fixture test for the sqrt_price_x64 u128 override. Its current coverage requires mainnet RPC and integration-tests, so default test runs won’t catch regressions in that write path.

Review was static; tests were not run.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

This PR adds PancakeSwap CLMM templates (pancakeswap-clmm-custom, -pool-state, -amm-config), its vendored IDL, a how-to README, registry wiring and tests. Unit tests check that all 22 fee-tier PDAs derive to their documented addresses. Live tests fetch real mainnet accounts: one round-trips a pool, one checks each AmmConfig against its tier, and one confirms an override changes only the targeted bytes.

Overall the PR is clean and mirrors the Raydium CLMM setup closely. The IDL address matches the program id, the status bit meanings match the program, and the template count and protocol assertions are updated consistently.

Issues

  • Unrelated CI change: .github/workflows/claude-review.yml is not mentioned in the PR description and has nothing to do with PancakeSwap.
    • It should go in its own PR so it can be reviewed separately.
    • It pastes the PR title and body straight into the prompt (${{ github.event.pull_request.body }}), so anyone who can open a same-repo PR can inject instructions into the review. The read-only token and limited allowedTools contain the damage, but the risk should be stated in that PR.
  • Duplicated llm_context: the PRICE/TICK, TICK ARRAYS, LIQUIDITY RULE and VAULTS blocks appear word for word in both pool templates, and are probably close copies of the Raydium v3 text too. If the engine supports shared/protocol-level context or YAML anchors (&/*), using them would stop these copies from drifting apart.
  • Owner check: the README admits that a PancakeSwap template pointed at a Raydium pool writes it without complaint. pancakeswap-clmm-pool-state takes any pubkey, so a cheap check would help: reject the override, or at least warn, when the forked account's owner is not HpNfyc…. This could be a follow-up.
  • Minor README gap: in the "Number formats" table, the sqrt_price_x64 and liquidity rows have an empty Example cell. Fill them in or drop the column for those rows.

smaller than token_mint_1's (compare the decoded bytes, not the base58 string).
The pool PDA is ["pool", amm_config, token_mint_0, token_mint_1] in that exact
order, so swapping the two mints derives a different, almost certainly empty,
address. token_mint_0/token_mint_1 are plain property_ref seeds here and the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The template doesn't check the mint order, and the README admits a reversed pair silently derives an empty address. With fetchBeforeUse: true, does the materializer then write a brand-new account at that address, or fail? If it writes one, the user ends up with a bogus 1544-byte account that no swap uses. Either way the scenario 'succeeds' while doing nothing useful. It's worth confirming what happens, and ideally the resolver should sort the two property_ref mints (or reject unsorted ones) for CLMM pool seeds.

- path: status
label: Pool Status
description: "Disable bitmask (u8): bit0 open/increase liquidity, bit1 decrease liquidity, bit2 collect fee, bit3 collect reward, bit4 swap; 0 = all enabled"
llm_context: |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Lines 345–383 repeat lines 245–299 of the custom template almost word for word, and those are close copies of the Raydium v3 text. Consider a YAML anchor (llm_context: &clmm_ctx) or shared protocol-level context so fixes to the liquidity/tick rules land in one place.

Comment thread crates/core/src/scenarios/registry.rs Outdated

#[test]
fn pancakeswap_template_derives_a_live_pool() {
let registry = TemplateRegistry::new();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The test name says derives_a_live_pool, but it only does an offline PDA derivation. Two suggestions:

  • Rename it, e.g. pancakeswap_custom_template_derives_known_pool_address.
  • Add a comment naming the pair. CGiwPp7b… is not documented anywhere else in the PR, so it's unclear which pool 1Piz3kL… is and why the mints are in this order.

const SOL_USDC_POOL: Pubkey =
Pubkey::from_str_const("DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ");

const LIQUIDITY_RANGE: std::ops::Range<usize> = 237..253;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

These hard-coded offsets (237..253, 253..269, 269..273, 389) duplicate the IDL layout. A cheap guard would help:

  • Assert the live pool's length is 1544 (as the yaml documents) and that it starts with the PoolState discriminator.
  • Then a layout upgrade fails with a clear message, not as an unexplained diff of bytes outside the overridden fields.


| You'll see | It means | Example |
|---|---|---|
| `sqrt_price_x64` | `sqrt(price_raw) x 2^64`, as a decimal **string** | |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The Example cells for sqrt_price_x64 and liquidity are empty. Add a sample value (e.g. the SOL/USDC pool's current sqrt price) or remove the column for these rows.

Pull request title and body:
----
${{ github.event.pull_request.title }}
${{ github.event.pull_request.body }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This workflow is unrelated to the PancakeSwap feature and should move to its own PR. It also puts the untrusted PR body directly into the model prompt. The read-only token and restricted tools limit the impact, but prompt injection can still steer the posted review. Consider stating that risk, or leaving the body out.

@92Infinitus92
92Infinitus92 force-pushed the feat/scenarios/raydium branch from a9eba96 to 691c199 Compare October 11, 2026 05:46
@92Infinitus92
92Infinitus92 changed the base branch from feat/scenarios/raydium to feat/scenarios/override/pancakeswap-support October 12, 2026 05:31
@92Infinitus92
92Infinitus92 force-pushed the feat/scenarios/pancakeswap branch from 4e3b1ea to 1fd2035 Compare October 12, 2026 05:31

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Overview. This PR adds PancakeSwap CLMM support: a vendored IDL, three templates (pancakeswap-clmm-custom, -pool-state and -amm-config), a README, and unit and integration tests. It also adds a collection-level llm_context that is prepended to each template's own context, and it expands the description of the MCP call_surfnet_rpc params.

What I checked.

  • The hard-coded byte offsets match the Raydium CLMM PoolState / AmmConfig layout:
    • PoolState: mints at 73 and 105, token_vault_0 at 137, liquidity at 237, sqrt_price_x64 at 253, tick_current at 269, status at 389, size 1544.
    • AmmConfig: trade_fee_rate at 47, tick_spacing at 51, size 117.
  • The PDA seeds and the price/tick formulas are consistent.
  • The tick-crossing rule in the README is correct (up: old < t <= new, add; down: new < t <= old, subtract).
  • The tests are well targeted. Deriving every fee tier's address offline, and asserting that only the targeted bytes change, are good guards.

Concerns and nits.

  • Out-of-scope workflow. .github/workflows/claude-review.yml is unrelated to PancakeSwap and isn't mentioned in the PR body. Consider splitting it into its own PR. As written it is reasonably hardened (read-only token for the Claude job, fork PRs skipped, pinned SHAs). However, the PR title and body are interpolated straight into the prompt, so a same-repo author can steer the review text.
  • Shared llm_context reaches every template. It is now also prepended to pancakeswap-clmm-amm-config, which gets the full pool-search and price-shock guidance (see the inline comment).
  • Tests depend on the public mainnet RPC. The integration tests rely on api.mainnet-beta.solana.com, which is often rate-limited. They are feature-gated, so this is acceptable, but it's worth noting for CI flakiness.

Overall this looks correct and ready, apart from the scope and nit items above.

description: Select a token mint address from verified tokens
source: verified_tokens

llm_context: |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This collection-level llm_context is now prepended to every template, including pancakeswap-clmm-amm-config. That template doesn't need the pool-search, fetchBeforeUse and price/liquidity guidance, which costs tokens and may lead an agent to look up pools when it only wants to change fees. Consider moving the PRICE paragraph into the two pool templates' own llm_context, or noting here that the pool guidance only applies to the pool templates.

let account_type = entry
.idl_account_name
.unwrap_or_else(|| default_account_type.clone());
let llm_context = match (&self.llm_context, entry.llm_context) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: when only own is present, it is returned untrimmed. When both are present, shared is trimmed but own is not. The result is fine for YAML block scalars, but (None, own) => own, (shared, None) => shared.clone() would read more clearly than own.or_else(|| shared.clone()) inside a catch-all arm.

pub method: String,
#[schemars(description = "The parameters to pass to the RPC method")]
#[schemars(
description = "The parameters to pass to the RPC method. Wrap every value at every depth by its type: a string as {\"String\":\"...\"}, a whole number as {\"Number\":5}, a boolean as {\"Bool\":true}, a list as {\"Array\":[...]} and an object as {\"Object\":{\"key\":<wrapped value>}}; object keys stay plain. Example for getProgramAccounts with a filter: [{\"String\":\"<program id>\"},{\"Object\":{\"encoding\":{\"String\":\"base64\"},\"filters\":{\"Array\":[{\"Object\":{\"memcmp\":{\"Object\":{\"offset\":{\"Number\":0},\"bytes\":{\"String\":\"<base58>\"}}}}}]}}}]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The description lists String/Number/Bool/Array/Object but leaves out Null, which is a unit variant serialized as the plain string "Null". That one is easy to get wrong. It also doesn't say that Number is i64, so u64 values above i64::MAX and all fractional numbers must be passed as strings. Mentioning both would save the LLM a failed call.

are numerically smaller, not the smaller base58 string. A reversed pair derives an empty address
and nothing checks it.

**Check the owner.** The layouts match Raydium's, so a PancakeSwap template pointed at a Raydium

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This warns about the owner mismatch, but nothing in the templates enforces it. Since the IDL is resolved by account owner, a pancakeswap-clmm-pool-state override on a Raydium pool silently succeeds. If the engine can compare the template's program id with the fetched owner, a warning there would turn this limitation into a detectable error. Worth a follow-up issue if it's out of scope here.

fee_rate_bps: 10
derived_address: 5szFcjKA7UU93nhgb3fE1o1cfcurwpFQEzywZyb2qAYF
- id: index_11
label: "Fee tier 0.15% (tick spacing 10)"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ou ou ou, let's move these hardcoded values to the front-end please, and here to make it generic so one could provide it from externally

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Overview

Adds PancakeSwap CLMM templates (YAML and vendored IDL), a collection-level llm_context that gets prepended to each template's own context, live integration tests, and a shared diff_indices test helper. It also bundles some unrelated changes: a new claude-review.yml workflow and a rewrite of the MCP call_surfnet_rpc params description.

I checked the hard-coded byte offsets against the PoolState layout and they're correct (amm_config 9, mints 73/105, vault0 137, liquidity 237, sqrt_price 253, tick 269, status 389). The README math also checks out: the sqrt_price_x64 example for 100 USDC/SOL, the tick formula, and the rule for which ticks are crossed and what happens to liquidity_net. The llm_context merge in to_override_templates is simple and has a unit test.

Issues

  • The PR description no longer matches the code. It lists a pancakeswap-clmm-custom template and "22 fee tiers by config index, address derived". After 22d0247 there are only 2 templates, and amm-config is addressed by a plain pubkey. Please update the body. The test-plan line "check every fee tier against its live AmmConfig" is out of date too: the tests now check only the SOL/USDC pool's config.
  • Unrelated changes. The CI workflow (.github/workflows/claude-review.yml) and the MCP schema description are separate concerns. They'd be easier to review and revert as their own PRs. The workflow puts the PR body straight into the prompt; fork PRs are skipped, so this only matters for same-repo branches.
  • The shared llm_context repeats itself. The collection context (pool lookup plus the PRICE rule) is now prepended to amm-config as well. Both that and the template's own context explain how to read amm_config at offset 9, so there's some duplication. That's fine, but it's worth knowing before you add more templates.
  • Minor: CLMM pools store mints ordered so that mint0 < mint1. Telling the LLM to sort the two mints by bytes and run one getProgramAccounts call would replace the "try both orders" instruction and halve the RPC calls.


PancakeSwap's concentrated-liquidity AMM on Solana, a fork of Raydium CLMM with the same account
layouts. Two templates: a pool, and the fee tier a pool points to. Units and rules match
[Raydium CLMM](../raydium/v3/README.md); only the program, pools and fee tiers differ.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

../raydium/v3/README.md doesn't exist in this branch: protocols/raydium/v3/ only has idl.json and overrides.yaml. If #21 adds that README, make sure this PR merges after it. Otherwise the link is broken, and the line "Units and rules match Raydium CLMM" sends readers to nothing.


Set fetchBeforeUse: true.

PRICE: do not move a pool's price by hand. sqrt_price_x64, tick_current and liquidity must change

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The collection-level context tells the LLM never to move the price by hand, yet pancakeswap-clmm-pool-state exposes sqrt_price_x64, tick_current and liquidity as editable properties right below. An LLM (or a user in the form UI) gets mixed signals. Consider one of these:

  • drop sqrt_price_x64 and tick_current from the template's properties, keeping only the coupled preset path in Studio; or
  • state the coupling inside the property descriptions too (e.g. on liquidity: "must be recomputed from tick arrays when the price moves"), so non-LLM users see the warning.

PancakeSwap CLMM, program HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq, a fork of Raydium CLMM.

FIND A POOL BY PAIR: resolve both mints with get_token_address, then call getProgramAccounts on the
program with filters dataSize 1544 and memcmp of the two mints at offsets 73 and 105, once in each

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CLMM requires mint0 < mint1 (by bytes), so the order is deterministic. Telling the LLM to sort the two mints and run a single getProgramAccounts call is cheaper and less error-prone than "once in each order (only one returns pools)".


**The destination tick array must exist.** A swap resumes from the array covering the new tick,
PDA `["tick_array", pool, start_index as i32 big-endian]` with 60 ticks of `tick_spacing` each.
Studio refuses a move onto a missing array.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Studio refuses a move onto a missing array" describes behaviour in another repo (surfpool-web-ui#22) that may not be merged or released yet. Consider linking the PR or phrasing this as "the Studio preset checks…" so the README doesn't promise something Surfpool itself doesn't do.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

Adds PancakeSwap CLMM (a Raydium CLMM fork) as a YAML + IDL protocol with two templates (pancakeswap-clmm-pool-state, pancakeswap-clmm-amm-config). It also adds a collection-level llm_context that is prepended to each template's own context, moves diff_indices into tests/helpers, expands the call_surfnet_rpc params description, and adds live mainnet integration tests.

I checked the hard-coded values against the Raydium layout and they're correct:

  • PoolState offsets: amm_config 9, mints 73/105, token_vault_0 137, liquidity 237, sqrt_price_x64 253, tick_current 269, status 389. Total size 1544.
  • AmmConfig: size 117.
  • Status bits: bit 4 is swap.
  • Tick array PDA: big-endian start_index.
  • Tick formula: floor(2·ln(sqrt/2^64)/ln(1.0001)).
  • Crossing rules: old < t <= new going up, new < t <= old going down.

The code is in good shape. Remaining points:

  • The PR description is out of date. It lists a third template, pancakeswap-clmm-custom, and says pancakeswap-clmm-amm-config covers "22 fee tiers by config index, address derived". After 22d0247 there are only two templates, and the AmmConfig is addressed by pubkey read from the pool. Please update the body so reviewers and release notes match the code.
  • Unrelated change in this PR. .github/workflows/claude-review.yml has nothing to do with PancakeSwap and should go in its own PR. Within it, the PR title and body are put straight into the prompt. Fork PRs are skipped, so the exposure is limited, but untrusted text is still being placed into an instruction prompt.
  • Collection-level llm_context has no raw_layout: false coverage. The new unit test only covers a raw_layout: true collection. That's fine for testing the merge logic. PancakeSwap is the only YAML that uses the field so far, so the change is low risk.
  • The "known limitation" could be guarded. The PancakeSwap template writes Raydium pools without complaint. If the engine already knows the template's program id, a warning or an owner check at materialization time would turn that README caveat into a guard.

let account_type = entry
.idl_account_name
.unwrap_or_else(|| default_account_type.clone());
let llm_context = match (&self.llm_context, entry.llm_context) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Merging the contexts looks right. When only the shared context exists, it's cloned once per template. That's fine, but consider documenting on the struct field that whitespace is trimmed only in the (Some, Some) case. A shared context without a trailing newline would be joined differently from one with it, and the asymmetry isn't obvious.

pub method: String,
#[schemars(description = "The parameters to pass to the RPC method")]
#[schemars(
description = "The parameters to pass to the RPC method. Wrap every value at every depth by its type: a string as {\"String\":\"...\"}, a whole number as {\"Number\":5}, a boolean as {\"Bool\":true}, a list as {\"Array\":[...]} and an object as {\"Object\":{\"key\":<wrapped value>}}; object keys stay plain. Example for getProgramAccounts with a filter: [{\"String\":\"<program id>\"},{\"Object\":{\"encoding\":{\"String\":\"base64\"},\"filters\":{\"Array\":[{\"Object\":{\"memcmp\":{\"Object\":{\"offset\":{\"Number\":0},\"bytes\":{\"String\":\"<base58>\"}}}}}]}}}]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The description lists String, Number, Bool, Array and Object, but not Null. JsonValue::Null is a unit variant, so it serializes as the bare string "Null", not {"Null":...}. An LLM following this text has no way to pass a null (for example an optional positional param). Add null as "Null". It's also worth noting that Number is i64, so fractional values aren't accepted.

whose vault holds the most; name it. If neither order returns a pool, recheck the mints once, then
ask for the pool address. A pool address the user gives is used as is.

Set fetchBeforeUse: true.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

fetchBeforeUse: true is a scenario/override flag. Here it sits in the collection-wide context next to the getProgramAccounts recipe, so it applies to both templates. That's intended, but say where the flag goes (on the override instance), as the per-template contexts do for account. Otherwise the LLM may put it inside values.

#[tokio::test]
async fn pool_amm_config_at_offset_9_is_a_live_amm_config_that_round_trips() {
let pool = fetch(&[SOL_USDC_POOL]).await.remove(0).data;
let config_address = Pubkey::try_from(&pool[AMM_CONFIG_RANGE]).expect("32 bytes");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The pool and its AmmConfig are fetched in two separate requests. That's harmless here because only the address is used. The fetch doc comment says it fetches "in one request, so every account returned is from the same slot", but that guarantee doesn't hold across these two calls.

`DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ` (0.01% fee, tick spacing 10). Pools are also listed
at `https://solana.pancakeswap.finance/liquidity-pools/`.

**Check the owner.** The layouts match Raydium's, so a PancakeSwap template pointed at a Raydium

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This documents the IDL-by-owner limitation but offers no mitigation. Consider stating the PancakeSwap program id inline here (HpNfyc2S...) as the owner to check, so readers know what to compare owner against.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants