Skip to content

Conversation

@St0rmBr3w
Copy link
Contributor

@St0rmBr3w St0rmBr3w commented Apr 9, 2025

⚠️ Prerequisites

  • Anchor: v0.29.0
  • Solana CLI: v1.17.31

    Builds on Solana CLI v1.18.x (and above) will hit a “stack offset exceeded” error due to changes in codegen.

In this PR:

  • Implements a Raydium Composer for OFT’s on Solana that calls the swap_v2 method from Raydium AMM V3 via the CPI helper.
  • Utilizes the raydium-cpi and raydium-cpi-example repositories (both targeting Anchor 0.29.0) to integrate CLMM swap functionality. The implementation shows how to trigger the swap through the lzCompose method.
  • Integrates with LayerZero messaging so that after the swap CPI is executed, the corresponding LayerZero compose state is cleared.

Testing & Validation:

  • Verified that the minimal context for the swap CPI meets the Raydium AMM V3 requirements.
  • Ensured proper integration with LayerZero messaging—after executing the swap, the compose message is cleared as expected.
  • Reviewed the generated code (using tools like cargo expand) to confirm that only the necessary accounts and fields are compiled.
  • Currently testing framework using the solana-local-validator and cloning the necessary programs:
mattkrak ~/Documents/codebase/devtools/examples/oft-solana-composer-library [feat/oft-solana-composer-example] $ solana-test-validator --reset   
  --clone CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK
  --clone 4BLNHtVe942GSs4teSZqGX24xwKNkqU7bGgNn3iUiUpw
  --clone D2bXjvT1xDiymTeX2mHqf9WGHkSVr2hPoHJiEg2jfVjL \        # PoolState PDA
  --clone Cv3s57YQzJRp988qvXPfZN5xX7BUFcgB1ycA9jzSrh2n \        # ObservationState PDA
  --clone 7QQMcPemiksr3288w42WtXmSJ3D9mTeMKykDosyMAdd2 \        # TickArray Lower
  --clone e4GKdBJg5TQZWaHYgYvpSDfDR3fGWKW2H2bQvFNwrnP \        # TickArray Current
  --clone HNrMx2ZTfDmJwMAHEW4whcdQErV553vQYht17xovpTVN \        # TickArray Upper
  --clone 5Nb7bdyi4jkMdA8Xqmt72HS1fpkGRQ573Gf8PJeGunsy \        # Input vault PDA (USDe)
  --clone sUfgz2jsDhN8qn1PrkWr9pVnUrLqqL1yB7WAnCj62Xz \        # Output vault PDA (USDC)
  --clone 9ofdGvb6jSrK5o3AkFNYKarJQSupa8H24vcv4hQAFpPr \        # Pool authority PDA
  --clone DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT \        # USDe mint
  --clone EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \        # USDC mint

Build Errors (when using Solana CLI ≥ 1.18.x)

attkrak ~/…/composer-library [feat/oft-solana-composer-example] $ anchor build
Error: Function … Stack offset of 4608 exceeded max offset of 4096 by 512 bytes, please minimize large stack variables
    Finished release [optimized] target(s) in 0.26s
    Finished test [unoptimized + debuginfo] target(s) in 0.48s
…

@St0rmBr3w St0rmBr3w requested a review from ryandgoulding April 10, 2025 23:02
@ziming-zung
Copy link
Contributor

lz_compose Flow

  1. The offchain executor first retrieves the data from the lz_compose_types_accounts PDA to identify which accounts are needed for the lz_compose_types instruction
  2. The executor then calls the lz_compose_types instruction with these accounts, which returns the complete list of accounts needed for lz_compose call
  3. The executor assembles all these accounts and calls lz_compose
  4. Inside lz_compose, this composer program should:
    • Validate the message is from the expected OFT (stored in composer pda)
    • Perform the Raydium swap via CPI call
    • Clear the compose message state via the clear_compose CPI call
    • Emit events

After a thorough review, I have some comments.

  1. For the init_composer instruction:
    I recommend implementing two clearly defined PDA in this instruction:

    a) The composer PDA:
    - Can be derived using a seed pattern such as [COMPOSER_SEED, oft_pda.key()]
    - Should store critical data like:
    • The OFT PDA address for validation during compose operations
    • Any configuration
    - This account acts as the main program state and authority

    b) The lz_compose_types_accounts PDA:
    - Must be derived specifically with [LZ_COMPOSE_TYPES_SEED, composer.key()]
    - Try to keep only necessary account addresses, which cannot be deterministically derived at runtime through PDA
    This mode ensures that the offchain executor can correctly discover all required accounts

  2. For the lz_compose_types instruction:

    • This instruction functions as a view function and should not modify any state
      • All account annotations should reflect this by removing #[account(mut)] macro
    • The implementation should ensure that accounts appear in the correct order for both the swap operation and subsequent clearing of the compose state:
      • First retrieve the base accounts needed for swap operations
      • Then append the accounts required by get_accounts_for_clear_compose
      • Return a complete, ordered list of accounts that the executor will provide to lz_compose
  3. For the lz_compose instruction:

    • Add some validation checks, like this:
    require(params.from == oft_pda);
    require(params.to == composer_pda);

@St0rmBr3w St0rmBr3w force-pushed the feat/oft-solana-composer-example branch from 75caabb to 3e59a46 Compare April 14, 2025 14:54
@socket-security
Copy link

socket-security bot commented Apr 14, 2025

No dependency changes detected. Learn more about Socket for GitHub ↗︎

👍 No dependency changes detected in pull request

@St0rmBr3w
Copy link
Contributor Author

This PR is blocked until the implementation of the lz_compose_types_with_alt and lz_compose_with_alt

@St0rmBr3w St0rmBr3w changed the title feat: add solana composer example DEVREL-431 feat: add solana composer example Jun 13, 2025
@cooldev900
Copy link

@St0rmBr3w @ziming-zung
When do you expect this PR could be merged?
I am looking forward to an example like this.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants