1- use anchor_lang:: { prelude:: * , Accounts , Key , Result , ToAccountInfo } ;
2-
3- use crate :: {
4- error:: ErrorCode ,
5- math:: oracle:: { is_oracle_valid_for_action, DriftAction } ,
6- msg,
7- state:: {
8- lp_pool:: { AmmConstituentDatum , AmmConstituentMappingFixed , LPPool , WeightValidationFlags } ,
9- perp_market_map:: MarketSet ,
10- state:: State ,
11- user:: MarketType ,
12- zero_copy:: { AccountZeroCopy , ZeroCopyLoader } ,
1+ use anchor_lang:: { prelude:: * , Accounts , Key , Result } ;
2+ use anchor_spl:: token_interface:: { Mint , TokenAccount , TokenInterface } ;
3+
4+ use crate :: error:: ErrorCode ;
5+ use crate :: math:: {
6+ oracle:: { is_oracle_valid_for_action, DriftAction } ,
7+ safe_math:: SafeMath ,
8+ } ;
9+ use crate :: msg;
10+ use crate :: state:: spot_market:: SpotBalanceType ;
11+ use crate :: state:: {
12+ lp_pool:: {
13+ AmmConstituentDatum , AmmConstituentMappingFixed , Constituent , LPPool , WeightValidationFlags ,
1314 } ,
14- validate,
15+ perp_market_map:: MarketSet ,
16+ state:: State ,
17+ user:: MarketType ,
18+ zero_copy:: { AccountZeroCopy , ZeroCopyLoader } ,
1519} ;
20+ use crate :: validate;
21+
1622use solana_program:: sysvar:: clock:: Clock ;
1723
1824use super :: optional_accounts:: { load_maps, AccountMaps } ;
25+ use crate :: controller:: spot_balance:: update_spot_market_cumulative_interest;
26+ use crate :: controller:: token:: { receive, send_from_program_vault} ;
27+ use crate :: instructions:: constraints:: * ;
1928use crate :: state:: lp_pool:: { AMM_MAP_PDA_SEED , CONSTITUENT_TARGET_WEIGHT_PDA_SEED } ;
2029
2130pub fn handle_update_constituent_target_weights < ' c : ' info , ' info > (
2231 ctx : Context < ' _ , ' _ , ' c , ' info , UpdateConstituentTargetWeights < ' info > > ,
2332 constituent_indexes : Vec < u16 > ,
2433) -> Result < ( ) > {
34+ msg ! ( "HIHI!" ) ;
2535 let lp_pool = & ctx. accounts . lp_pool . load ( ) ?;
2636 let state = & ctx. accounts . state ;
37+ msg ! ( "datalen: {}" , ctx. accounts. constituent_target_weights. data_len( ) ) ;
2738 let mut constituent_target_weights = ctx. accounts . constituent_target_weights . load_zc_mut ( ) ?;
2839
2940 let num_constituents = constituent_target_weights. len ( ) ;
3041 let exists_invalid_constituent_index = constituent_indexes
3142 . iter ( )
3243 . any ( |index| * index as u32 >= num_constituents) ;
44+ msg ! ( "num_constituents: {} " , num_constituents) ;
3345
3446 validate ! (
3547 !exists_invalid_constituent_index,
@@ -44,6 +56,7 @@ pub fn handle_update_constituent_target_weights<'c: 'info, 'info>(
4456 AmmConstituentDatum ,
4557 AmmConstituentMappingFixed ,
4658 > = ctx. accounts . amm_constituent_mapping . load_zc ( ) ?;
59+ msg ! ( "amm constituent mapping weights: {} datalen: {}" , amm_constituent_mapping. len( ) , ctx. accounts. amm_constituent_mapping. data_len( ) ) ;
4760
4861 let AccountMaps {
4962 perp_market_map,
@@ -100,6 +113,150 @@ pub fn handle_update_constituent_target_weights<'c: 'info, 'info>(
100113 Ok ( ( ) )
101114}
102115
116+ #[ access_control(
117+ fill_not_paused( & ctx. accounts. state)
118+ ) ]
119+ pub fn handle_lp_pool_swap < ' c : ' info , ' info > (
120+ ctx : Context < ' _ , ' _ , ' c , ' info , LPSwap < ' info > > ,
121+ in_market_index : u16 ,
122+ out_market_index : u16 ,
123+ in_amount : u64 ,
124+ min_out_amount : u64 ,
125+ ) -> Result < ( ) > {
126+ validate ! (
127+ in_market_index != out_market_index,
128+ ErrorCode :: InvalidSpotMarketAccount ,
129+ "In and out spot market indices cannot be the same"
130+ ) ?;
131+
132+ let slot = Clock :: get ( ) ?. slot ;
133+ let now = Clock :: get ( ) ?. unix_timestamp ;
134+ let state = & ctx. accounts . state ;
135+ let lp_pool = & ctx. accounts . lp_pool . load ( ) ?;
136+
137+ let mut in_constituent = ctx. accounts . in_constituent . load_mut ( ) ?;
138+ let mut out_constituent = ctx. accounts . out_constituent . load_mut ( ) ?;
139+
140+ let in_constituent_token_account = & ctx. accounts . constituent_in_token_account ;
141+ let out_constituent_token_account = & ctx. accounts . constituent_out_token_account ;
142+
143+ let constituent_target_weights = ctx. accounts . constituent_target_weights . load_zc ( ) ?;
144+
145+ let AccountMaps {
146+ perp_market_map,
147+ spot_market_map,
148+ mut oracle_map,
149+ } = load_maps (
150+ & mut ctx. remaining_accounts . iter ( ) . peekable ( ) ,
151+ & MarketSet :: new ( ) ,
152+ & MarketSet :: new ( ) ,
153+ slot,
154+ Some ( state. oracle_guard_rails ) ,
155+ ) ?;
156+
157+ let mut in_spot_market = spot_market_map. get_ref_mut ( & in_market_index) ?;
158+ let mut out_spot_market = spot_market_map. get_ref_mut ( & out_market_index) ?;
159+
160+ let in_oracle_id = in_spot_market. oracle_id ( ) ;
161+ let out_oracle_id = out_spot_market. oracle_id ( ) ;
162+
163+ let in_oracle = * oracle_map. get_price_data ( & in_oracle_id) ?;
164+ let out_oracle = * oracle_map. get_price_data ( & out_oracle_id) ?;
165+
166+ update_spot_market_cumulative_interest ( & mut in_spot_market, Some ( & in_oracle) , now) ?;
167+
168+ update_spot_market_cumulative_interest ( & mut out_spot_market, Some ( & out_oracle) , now) ?;
169+
170+ let in_constituent_balance =
171+ in_constituent. get_full_balance ( in_constituent_token_account. amount ) ?;
172+ msg ! (
173+ "in_constituent: {}, in_constituent_balance: {}" ,
174+ in_constituent. constituent_index,
175+ in_constituent_balance
176+ ) ;
177+ let out_constituent_balance =
178+ out_constituent. get_full_balance ( out_constituent_token_account. amount ) ?;
179+ msg ! (
180+ "out_constituent: {}, out_constituent_balance: {}" ,
181+ out_constituent. constituent_index,
182+ out_constituent_balance
183+ ) ;
184+
185+ let in_target_weight =
186+ constituent_target_weights. get_target_weight ( in_constituent. constituent_index ) ?;
187+ let out_target_weight =
188+ constituent_target_weights. get_target_weight ( out_constituent. constituent_index ) ?;
189+
190+ let ( in_amount, out_amount, in_fee, out_fee) = lp_pool. get_swap_amount (
191+ & in_oracle,
192+ & out_oracle,
193+ & in_constituent,
194+ & out_constituent,
195+ & in_spot_market,
196+ & out_spot_market,
197+ in_constituent_token_account. amount ,
198+ out_constituent_token_account. amount ,
199+ in_target_weight,
200+ out_target_weight,
201+ in_amount,
202+ ) ?;
203+ let out_amount_net_fees = if out_fee > 0 {
204+ out_amount. safe_sub ( out_fee. unsigned_abs ( ) as u64 ) ?
205+ } else {
206+ out_amount. safe_add ( out_fee. unsigned_abs ( ) as u64 ) ?
207+ } ;
208+
209+ validate ! (
210+ out_amount_net_fees >= min_out_amount,
211+ ErrorCode :: SlippageOutsideLimit ,
212+ format!(
213+ "Slippage outside limit: out_amount_net_fees({}) < min_out_amount({})" ,
214+ out_amount_net_fees, min_out_amount
215+ )
216+ . as_str( )
217+ ) ?;
218+
219+ in_constituent. record_swap_fees ( in_fee) ?;
220+ out_constituent. record_swap_fees ( out_fee) ?;
221+
222+ // interactions: CPIs
223+
224+ let ( transfer_from_vault, transfer_from_constituent) = out_constituent
225+ . get_amount_from_vaults_to_withdraw (
226+ out_constituent_token_account. amount ,
227+ out_amount_net_fees,
228+ ) ?;
229+
230+ // transfer in from user token account to token vault
231+ receive (
232+ & ctx. accounts . token_program ,
233+ & ctx. accounts . user_in_token_account ,
234+ & ctx. accounts . constituent_in_token_account ,
235+ & ctx. accounts . authority ,
236+ in_amount,
237+ & Some ( ( * ctx. accounts . in_market_mint ) . clone ( ) ) ,
238+ ) ?;
239+ ctx. accounts . constituent_in_token_account . reload ( ) ?;
240+
241+ // transfer out from token vault to constituent token account
242+ if transfer_from_vault > 0 {
243+ send_from_program_vault (
244+ & ctx. accounts . token_program ,
245+ & ctx. accounts . out_spot_market_vault ,
246+ & ctx. accounts . constituent_out_token_account ,
247+ & ctx. accounts . drift_signer ,
248+ state. signer_nonce ,
249+ transfer_from_vault,
250+ & Some ( ( * ctx. accounts . out_market_mint ) . clone ( ) ) ,
251+ ) ?;
252+ }
253+ ctx. accounts . constituent_out_token_account . reload ( ) ?;
254+
255+ // transfer out from constituent token account to user token account
256+
257+ Ok ( ( ) )
258+ }
259+
103260#[ derive( Accounts ) ]
104261#[ instruction(
105262 lp_pool_name: [ u8 ; 32 ] ,
@@ -127,3 +284,57 @@ pub struct UpdateConstituentTargetWeights<'info> {
127284 ) ]
128285 pub lp_pool : AccountLoader < ' info , LPPool > ,
129286}
287+
288+ #[ derive( Accounts ) ]
289+ pub struct LPSwap < ' info > {
290+ /// CHECK: forced drift_signer
291+ pub drift_signer : AccountInfo < ' info > ,
292+ pub state : Box < Account < ' info , State > > ,
293+ pub lp_pool : AccountLoader < ' info , LPPool > ,
294+ #[ account(
295+ mut ,
296+ seeds = [ CONSTITUENT_TARGET_WEIGHT_PDA_SEED . as_ref( ) , lp_pool. key( ) . as_ref( ) ] ,
297+ bump,
298+ ) ]
299+ /// CHECK: checked in ConstituentTargetWeightsZeroCopy checks
300+ pub constituent_target_weights : AccountInfo < ' info > ,
301+
302+ #[ account( mut ) ]
303+ pub constituent_in_token_account : Box < InterfaceAccount < ' info , TokenAccount > > ,
304+ #[ account( mut ) ]
305+ pub constituent_out_token_account : Box < InterfaceAccount < ' info , TokenAccount > > ,
306+
307+ #[ account( mut ) ]
308+ pub user_in_token_account : Box < InterfaceAccount < ' info , TokenAccount > > ,
309+ #[ account( mut ) ]
310+ pub user_out_token_account : Box < InterfaceAccount < ' info , TokenAccount > > ,
311+
312+ #[ account(
313+ mut ,
314+ constraint = & in_spot_market_vault. mint. eq( & in_market_mint. key( ) )
315+ ) ]
316+ pub in_spot_market_vault : Box < InterfaceAccount < ' info , TokenAccount > > ,
317+ #[ account(
318+ mut ,
319+ constraint = & out_spot_market_vault. mint. eq( & out_market_mint. key( ) )
320+ ) ]
321+ pub out_spot_market_vault : Box < InterfaceAccount < ' info , TokenAccount > > ,
322+
323+ #[ account( mut ) ]
324+ pub in_constituent : AccountLoader < ' info , Constituent > ,
325+ #[ account( mut ) ]
326+ pub out_constituent : AccountLoader < ' info , Constituent > ,
327+
328+ #[ account(
329+ constraint = in_market_mint. key( ) == in_constituent. load( ) ?. mint,
330+ ) ]
331+ pub in_market_mint : Box < InterfaceAccount < ' info , Mint > > ,
332+ #[ account(
333+ constraint = out_market_mint. key( ) == out_constituent. load( ) ?. mint,
334+ ) ]
335+ pub out_market_mint : Box < InterfaceAccount < ' info , Mint > > ,
336+
337+ pub authority : Signer < ' info > ,
338+
339+ pub token_program : Interface < ' info , TokenInterface > ,
340+ }
0 commit comments