1+ use crate :: * ;
12use anchor_lang:: prelude:: * ;
2- use anchor_spl:: token:: { Token , TokenAccount } ;
3- use anchor_spl:: token_interface:: { Token2022 } ;
3+ use anchor_spl:: token:: { Token } ;
4+ use anchor_spl:: token_interface:: { Token2022 , TokenAccount , Mint } ;
45use raydium_clmm_cpi:: cpi:: accounts:: SwapSingleV2 ;
56use raydium_clmm_cpi:: cpi:: swap_v2;
6- use std:: str:: FromStr ;
7-
8- // LayerZero / OApp endpoint CPI helpers:
7+ use raydium_clmm_cpi:: {
8+ program:: RaydiumClmm ,
9+ states:: { AmmConfig , ObservationState , PoolState } ,
10+ } ;
911use oapp:: endpoint:: { instructions:: ClearComposeParams , ID as ENDPOINT_ID } ;
10- use oapp:: endpoint_cpi:: { clear_compose} ;
12+ use oapp:: endpoint_cpi:: clear_compose;
1113use oapp:: LzComposeParams ;
12-
13- // Use our minimal AmmV3 type instead of importing from the raydium_amm_v3 crate.
14- #[ derive( Clone , Debug ) ]
15- pub struct AmmV3 ;
16-
17- impl anchor_lang:: Id for AmmV3 {
18- fn id ( ) -> Pubkey {
19- Pubkey :: from_str ( "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK" ) . unwrap ( )
20- }
21- }
14+ use spl_memo;
2215
2316#[ derive( Accounts ) ]
2417pub struct LzCompose < ' info > {
25- #[ account( seeds = [ b"composer" ] , bump) ]
26- pub lz_program : AccountInfo < ' info > ,
18+ // Use the stored “oft” field as the unique seed.
19+ #[ account(
20+ mut ,
21+ seeds = [ COMPOSER_SEED , & composer. oft. to_bytes( ) ] ,
22+ bump = composer. bump
23+ ) ]
24+ pub composer : Account < ' info , Composer > ,
25+
26+ pub clmm_program : Program < ' info , RaydiumClmm > ,
27+ /// The user performing the swap.
2728 pub payer : Signer < ' info > ,
28- #[ account( seeds = [ b"authority" ] , bump) ]
29- pub authority : AccountInfo < ' info > ,
30- pub amm_config : AccountInfo < ' info > ,
29+
30+ /// The factory state to read protocol fees.
31+ #[ account( address = pool_state. load( ) ?. amm_config) ]
32+ pub amm_config : Box < Account < ' info , AmmConfig > > ,
33+
34+ /// The program account of the pool in which the swap will be performed.
3135 #[ account( mut ) ]
32- pub pool_state : AccountInfo < ' info > ,
36+ pub pool_state : AccountLoader < ' info , PoolState > ,
37+
38+ /// The user token account for input token.
3339 #[ account( mut ) ]
34- pub source_token_account : Account < ' info , TokenAccount > ,
40+ pub input_token_account : Box < InterfaceAccount < ' info , TokenAccount > > ,
41+
42+ /// The user token account for output token.
3543 #[ account( mut ) ]
36- pub dest_token_account : Account < ' info , TokenAccount > ,
44+ pub output_token_account : Box < InterfaceAccount < ' info , TokenAccount > > ,
45+
46+ /// The vault token account for input token.
3747 #[ account( mut ) ]
38- pub input_vault : AccountInfo < ' info > ,
48+ pub input_vault : Box < InterfaceAccount < ' info , TokenAccount > > ,
49+
50+ /// The vault token account for output token.
3951 #[ account( mut ) ]
40- pub output_vault : AccountInfo < ' info > ,
52+ pub output_vault : Box < InterfaceAccount < ' info , TokenAccount > > ,
53+
54+ /// The program account for the most recent oracle observation.
55+ #[ account( mut , address = pool_state. load( ) ?. observation_key) ]
56+ pub observation_state : AccountLoader < ' info , ObservationState > ,
57+
58+ /// SPL program for token transfers.
4159 pub token_program : Program < ' info , Token > ,
60+
61+ /// SPL program 2022 for token transfers.
4262 pub token_program_2022 : Program < ' info , Token2022 > ,
43- #[ account( mut ) ]
44- pub input_token_mint : AccountInfo < ' info > ,
45- #[ account( mut ) ]
46- pub output_token_mint : AccountInfo < ' info > ,
47- #[ account( mut ) ]
48- pub observation_state : AccountInfo < ' info > ,
49- /// CHECK: Required for memo instructions.
50- pub memo_program : AccountInfo < ' info > ,
63+
64+ /// CHECK: Must match spl_memo::id().
65+ #[ account( address = spl_memo:: id( ) ) ]
66+ pub memo_program : UncheckedAccount < ' info > ,
67+
68+ /// The mint of the input token vault.
69+ #[ account( address = input_vault. mint) ]
70+ pub input_vault_mint : Box < InterfaceAccount < ' info , Mint > > ,
71+
72+ /// The mint of the output token vault.
73+ #[ account( address = output_vault. mint) ]
74+ pub output_vault_mint : Box < InterfaceAccount < ' info , Mint > > ,
75+
76+ // Extra accounts required by the CPI.
77+ /// The authority account for the swap.
78+ pub authority : AccountInfo < ' info > ,
79+
80+ /// Tick arrays for the swap range.
5181 #[ account( mut ) ]
5282 pub tick_array_lower : AccountInfo < ' info > ,
5383 #[ account( mut ) ]
5484 pub tick_array_current : AccountInfo < ' info > ,
5585 #[ account( mut ) ]
5686 pub tick_array_upper : AccountInfo < ' info > ,
57- pub raydium_program : Program < ' info , AmmV3 > ,
5887}
5988
60- /// Processes the lz_compose instruction.
6189impl LzCompose < ' _ > {
6290 pub fn apply ( ctx : & mut Context < LzCompose > , params : & LzComposeParams ) -> Result < ( ) > {
6391 let msg = & params. message ;
@@ -66,38 +94,33 @@ impl LzCompose<'_> {
6694 let mut compose_from = [ 0u8 ; 32 ] ;
6795 compose_from. copy_from_slice ( & msg[ 40 ..72 ] ) ;
6896 let inner = & msg[ 72 ..] ;
69-
7097 let min_amount_out = u64:: from_be_bytes ( inner[ 0 ..8 ] . try_into ( ) . unwrap ( ) ) ;
7198
72- // Build the CPI accounts struct for Raydium's SwapSingleV2 .
99+ // Build CPI accounts struct.
73100 let cpi_accounts = SwapSingleV2 {
74101 payer : ctx. accounts . payer . to_account_info ( ) ,
75102 amm_config : ctx. accounts . amm_config . to_account_info ( ) ,
76103 pool_state : ctx. accounts . pool_state . to_account_info ( ) ,
77- input_token_account : ctx. accounts . source_token_account . to_account_info ( ) ,
78- output_token_account : ctx. accounts . dest_token_account . to_account_info ( ) ,
104+ input_token_account : ctx. accounts . input_token_account . to_account_info ( ) ,
105+ output_token_account : ctx. accounts . output_token_account . to_account_info ( ) ,
79106 input_vault : ctx. accounts . input_vault . to_account_info ( ) ,
80107 output_vault : ctx. accounts . output_vault . to_account_info ( ) ,
81108 observation_state : ctx. accounts . observation_state . to_account_info ( ) ,
82109 token_program : ctx. accounts . token_program . to_account_info ( ) ,
83110 token_program_2022 : ctx. accounts . token_program_2022 . to_account_info ( ) ,
84111 memo_program : ctx. accounts . memo_program . to_account_info ( ) ,
85- input_vault_mint : ctx. accounts . input_token_mint . to_account_info ( ) ,
86- output_vault_mint : ctx. accounts . output_token_mint . to_account_info ( ) ,
112+ input_vault_mint : ctx. accounts . input_vault_mint . to_account_info ( ) ,
113+ output_vault_mint : ctx. accounts . output_vault_mint . to_account_info ( ) ,
87114 } ;
88115
89- // Build the CPI context with the Raydium CLMM program.
90- let mut cpi_ctx =
91- CpiContext :: new ( ctx. accounts . raydium_program . to_account_info ( ) , cpi_accounts) ;
92-
93- // Attach remaining accounts in the exact order required.
116+ let mut cpi_ctx = CpiContext :: new ( ctx. accounts . clmm_program . to_account_info ( ) , cpi_accounts) ;
94117 cpi_ctx = cpi_ctx. with_remaining_accounts ( vec ! [
95118 ctx. accounts. payer. to_account_info( ) ,
96119 ctx. accounts. authority. to_account_info( ) ,
97120 ctx. accounts. amm_config. to_account_info( ) ,
98121 ctx. accounts. pool_state. to_account_info( ) ,
99- ctx. accounts. source_token_account . to_account_info( ) ,
100- ctx. accounts. dest_token_account . to_account_info( ) ,
122+ ctx. accounts. input_token_account . to_account_info( ) ,
123+ ctx. accounts. output_token_account . to_account_info( ) ,
101124 ctx. accounts. input_vault. to_account_info( ) ,
102125 ctx. accounts. output_vault. to_account_info( ) ,
103126 ctx. accounts. observation_state. to_account_info( ) ,
@@ -106,29 +129,28 @@ impl LzCompose<'_> {
106129 ctx. accounts. tick_array_upper. to_account_info( ) ,
107130 ] ) ;
108131
109- // Execute the CPI swap call.
110- swap_v2 (
111- cpi_ctx ,
112- amount_ld ,
113- min_amount_out ,
114- 0u128 , // sqrt_price_limit_x64 (adjust as needed)
115- true , // is_base_input
116- ) ? ;
132+ swap_v2 ( cpi_ctx , amount_ld , min_amount_out , 0u128 , true ) ? ;
133+
134+ // Use the stored "oft" field as the seed instead of a non-existent “id”.
135+ let seeds : & [ & [ u8 ] ] = & [
136+ COMPOSER_SEED ,
137+ & ctx . accounts . composer . oft . to_bytes ( ) ,
138+ & [ ctx . accounts . composer . bump ] ,
139+ ] ;
117140
118- // Clear the LayerZero compose message.
119141 let clear_params = ClearComposeParams {
120- from : compose_from . into ( ) ,
142+ from : params . from ,
121143 guid : params. guid ,
122144 index : params. index ,
123145 message : params. message . clone ( ) ,
124146 } ;
125147
126148 clear_compose (
127149 ENDPOINT_ID ,
128- ctx. accounts . lz_program . key ( ) ,
150+ ctx. accounts . composer . key ( ) ,
129151 & ctx. remaining_accounts ,
130- & [ b"composer" ] ,
152+ seeds ,
131153 clear_params,
132154 )
133155 }
134- }
156+ }
0 commit comments