Skip to main content

oil_api/
sdk.rs

1use solana_program::pubkey::Pubkey;
2use spl_associated_token_account::get_associated_token_address;
3use steel::*;
4
5use crate::{
6    consts::{AUCTION, BOARD, MINT_ADDRESS, SOL_MINT, TREASURY_ADDRESS},
7    instruction::{self, *},
8    state::*,
9};
10
11pub fn log(signer: Pubkey, msg: &[u8]) -> Instruction {
12    let mut data = Log {}.to_bytes();
13    data.extend_from_slice(msg);
14    Instruction {
15        program_id: crate::ID,
16        accounts: vec![AccountMeta::new(signer, true)],
17        data: data,
18    }
19}
20
21pub fn program_log(accounts: &[AccountInfo], msg: &[u8]) -> Result<(), ProgramError> {
22    // Derive Board PDA to use as signer for log instruction
23    let (board_address, _) = board_pda();
24    invoke_signed(&log(board_address, msg), accounts, &crate::ID, &[BOARD])
25}
26
27/// Log event for auction-based instructions (uses Auction PDA instead of Board)
28pub fn auction_program_log(accounts: &[AccountInfo], msg: &[u8]) -> Result<(), ProgramError> {
29    // Derive Auction PDA to use as signer for log instruction
30    let (auction_address, _) = auction_pda();
31    invoke_signed(&log(auction_address, msg), accounts, &crate::ID, &[AUCTION])
32}
33
34// let [signer_info, board_info, config_info, mint_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] = accounts else {
35// pub fn initialize(
36//     signer: Pubkey,
37//     barrel_authority: Pubkey,
38//     fee_collector: Pubkey,
39//     swap_program: Pubkey,
40//     var_address: Pubkey,
41//     admin_fee: u64,
42// ) -> Instruction {
43//     let board_address = board_pda().0;
44//     let config_address = config_pda().0;
45//     let mint_address = MINT_ADDRESS;
46//     let treasury_address = TREASURY_ADDRESS;
47//     let treasury_tokens_address = treasury_tokens_address();
48//     Instruction {
49//         program_id: crate::ID,
50//         accounts: vec![
51//             AccountMeta::new(signer, true),
52//             AccountMeta::new(board_address, false),
53//             AccountMeta::new(config_address, false),
54//             AccountMeta::new(mint_address, false),
55//             AccountMeta::new(treasury_address, false),
56//             AccountMeta::new(treasury_tokens_address, false),
57//             AccountMeta::new_readonly(system_program::ID, false),
58//             AccountMeta::new_readonly(spl_token::ID, false),
59//             AccountMeta::new_readonly(spl_associated_token_account::ID, false),
60//         ],
61//         data: Initialize {
62//             barrel_authority: barrel_authority.to_bytes(),
63//             fee_collector: fee_collector.to_bytes(),
64//             swap_program: swap_program.to_bytes(),
65//             var_address: var_address.to_bytes(),
66//             admin_fee: admin_fee.to_le_bytes(),
67//         }
68//         .to_bytes(),
69//     }
70// }
71
72// let [signer_info, automation_info, executor_info, miner_info, system_program] = accounts else {
73
74/// Set up automation for a miner. If the miner doesn't exist yet, pass a referrer to set it.
75/// If a referrer is provided and the miner is new, the referral account must be included.
76pub fn automate(
77    signer: Pubkey,
78    authority: Pubkey,
79    amount: u64,
80    deposit: u64,
81    executor: Pubkey,
82    fee: u64,
83    mask: u64,
84    strategy: u8,
85    reload: bool,
86    referrer: Option<Pubkey>,
87    pooled: bool,
88    is_new_miner: bool,
89) -> Instruction {
90    let automation_address = automation_pda(authority).0;
91    let miner_address = miner_pda(authority).0;
92    let config_address = config_pda().0;
93    let referrer_pk = referrer.unwrap_or(Pubkey::default());
94    
95    let mut accounts = vec![
96            AccountMeta::new(signer, true), // 0: signer (payer)
97            AccountMeta::new(authority, false), // 1: authority (user's wallet)
98            AccountMeta::new(automation_address, false), // 2: automation
99            AccountMeta::new(executor, false), // 3: executor
100            AccountMeta::new(miner_address, false), // 4: miner
101            AccountMeta::new_readonly(system_program::ID, false), // 5: system_program
102            AccountMeta::new_readonly(crate::ID, false), // 6: oil_program
103            AccountMeta::new_readonly(config_address, false), // 7: config
104    ];
105    
106    // Token accounts (user_wrapped_sol, automation_wrapped_sol, token_program, program_signer (optional), payer (optional), mint, ata_program)
107    // These are added by the client, not here in the SDK
108    
109    // Add referral account if referrer is provided and miner is new (for incrementing total_referred)
110    if is_new_miner && referrer.is_some() && referrer_pk != Pubkey::default() {
111        let referral_address = referral_pda(referrer_pk).0;
112        accounts.push(AccountMeta::new(referral_address, false));
113    }
114    
115    Instruction {
116        program_id: crate::ID,
117        accounts,
118        data: Automate {
119            amount: amount.to_le_bytes(),
120            deposit: deposit.to_le_bytes(),
121            fee: fee.to_le_bytes(),
122            mask: mask.to_le_bytes(),
123            strategy: strategy as u8,
124            reload: (reload as u64).to_le_bytes(),
125            referrer: referrer_pk.to_bytes(),
126            pooled: pooled as u8,
127        }
128        .to_bytes(),
129    }
130}
131
132/// Claim SOL rewards with single-tier referral system.
133/// 
134/// If the miner has a referrer, 1.0% of the claim goes to the referrer.
135/// 
136/// Account structure:
137/// - Base: signer, miner, system_program
138/// - If miner has referrer (required): [miner_referrer, referral_referrer]
139pub fn claim_sol(
140    signer: Pubkey,
141    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
142    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
143) -> Instruction {
144    let miner_address = miner_pda(signer).0;
145    
146    let mut accounts = vec![
147        AccountMeta::new(signer, true),
148        AccountMeta::new(miner_address, false),
149        AccountMeta::new_readonly(system_program::ID, false),
150    ];
151    
152    // Add referrer accounts if provided (required if miner has referrer)
153    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
154        accounts.push(AccountMeta::new(miner_pubkey, false));
155        accounts.push(AccountMeta::new(referral_pubkey, false));
156    }
157    
158    Instruction {
159        program_id: crate::ID,
160        accounts,
161        data: ClaimSOL {}.to_bytes(),
162    }
163}
164
165// let [signer_info, miner_info, mint_info, recipient_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] =
166
167/// Claim OIL rewards with single-tier referral system.
168/// 
169/// If the miner has a referrer, 1.0% of the claim goes to the referrer.
170/// 
171/// Account structure:
172/// - Base: signer, miner, mint, recipient, treasury, treasury_tokens, system_program, token_program, associated_token_program
173/// - If miner has referrer (required): [miner_referrer, referral_referrer, referral_referrer_oil_ata]
174pub fn claim_oil(
175    signer: Pubkey,
176    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
177    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
178    referrer_referral_oil_ata: Option<Pubkey>, // Referrer's referral OIL ATA (if miner has referrer)
179) -> Instruction {
180    let miner_address = miner_pda(signer).0;
181    let treasury_address = treasury_pda().0;
182    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
183    let recipient_address = get_associated_token_address(&signer, &MINT_ADDRESS);
184    
185    let mut accounts = vec![
186        AccountMeta::new(signer, true),
187        AccountMeta::new(miner_address, false),
188        AccountMeta::new(MINT_ADDRESS, false),
189        AccountMeta::new(recipient_address, false),
190        AccountMeta::new(treasury_address, false),
191        AccountMeta::new(treasury_tokens_address, false),
192        AccountMeta::new_readonly(system_program::ID, false),
193        AccountMeta::new_readonly(spl_token::ID, false),
194        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
195    ];
196    
197    // Add referrer accounts if provided (required if miner has referrer)
198    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
199        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
200        accounts.push(AccountMeta::new(miner_pubkey, false));
201        accounts.push(AccountMeta::new(referral_pubkey, false));
202        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
203    }
204    
205    Instruction {
206        program_id: crate::ID,
207        accounts,
208        data: ClaimOIL {}.to_bytes(),
209    }
210}
211
212
213pub fn close(signer: Pubkey, round_id: u64, rent_payer: Pubkey) -> Instruction {
214    let board_address = board_pda().0;
215    let round_address = round_pda(round_id).0;
216    let treasury_address = TREASURY_ADDRESS;
217    Instruction {
218        program_id: crate::ID,
219        accounts: vec![
220            AccountMeta::new(signer, true),
221            AccountMeta::new(board_address, false),
222            AccountMeta::new(rent_payer, false),
223            AccountMeta::new(round_address, false),
224            AccountMeta::new(treasury_address, false),
225            AccountMeta::new_readonly(system_program::ID, false),
226        ],
227        data: Close {}.to_bytes(),
228    }
229}
230
231/// Deploy SOL to prospect on squares.
232/// 
233/// This function uses native SOL transfers and is used for:
234/// - Regular wallets (signer == authority)
235/// - Automations (bot-executed deploys, signer != authority, using native SOL from automation account balance)
236/// 
237/// Pass a referrer pubkey for new miners to set up referral.
238/// Set `pooled` to true to join the mining pool (rewards shared proportionally).
239pub fn deploy(
240    signer: Pubkey,
241    authority: Pubkey,
242    amount: u64,
243    round_id: u64,
244    squares: [bool; 25],
245    referrer: Option<Pubkey>,
246    pooled: bool,
247) -> Instruction {
248    let automation_address = automation_pda(authority).0;
249    let board_address = board_pda().0;
250    let miner_address = miner_pda(authority).0;
251    let round_address = round_pda(round_id).0;
252    let entropy_var_address = entropy_rng_api::state::var_pda(board_address, 0).0;
253
254    let mut mask: u32 = 0;
255    for (i, &square) in squares.iter().enumerate() {
256        if square {
257            mask |= 1 << i;
258        }
259    }
260    
261    let referrer_pubkey = referrer.unwrap_or(Pubkey::default());
262    let referrer_bytes = referrer_pubkey.to_bytes();
263    // Match program logic: has_referrer = referrer != Pubkey::default() && referrer != authority
264    let has_referrer = referrer_pubkey != Pubkey::default() && referrer_pubkey != authority;
265
266    // Build accounts list - must match program structure:
267    // Oil accounts: base (8) + optional referral (1) = 8-9
268    // Entropy accounts: var + program = 2 (always exactly 2)
269    let mut accounts = vec![
270        AccountMeta::new(signer, true), // 0: signer
271        AccountMeta::new(authority, false), // 1: authority
272        AccountMeta::new(automation_address, false), // 2: automation
273        AccountMeta::new(board_address, false), // 3: board
274        AccountMeta::new(miner_address, false), // 4: miner
275        AccountMeta::new(round_address, false), // 5: round
276        AccountMeta::new_readonly(system_program::ID, false), // 6: system_program
277        AccountMeta::new_readonly(crate::ID, false), // 7: oil_program
278    ];
279    
280    // Add referral account if referrer is provided and not equal to authority (matches program logic)
281    if has_referrer {
282        let referral_address = referral_pda(referrer_pubkey).0;
283        accounts.push(AccountMeta::new(referral_address, false)); // referral (optional, in oil_accounts)
284    }
285    
286    // Entropy accounts (always exactly 2, come after all oil_accounts)
287    accounts.push(AccountMeta::new(entropy_var_address, false)); // entropy_var
288    accounts.push(AccountMeta::new_readonly(entropy_rng_api::ID, false)); // entropy_program
289
290    Instruction {
291        program_id: crate::ID,
292        accounts,
293        data: Deploy {
294            amount: amount.to_le_bytes(),
295            squares: mask.to_le_bytes(),
296            referrer: referrer_bytes,
297            pooled: if pooled { 1 } else { 0 },
298        }
299        .to_bytes(),
300    }
301}
302
303
304// let [pool, user_source_token, user_destination_token, a_vault, b_vault, a_token_vault, b_token_vault, a_vault_lp_mint, b_vault_lp_mint, a_vault_lp, b_vault_lp, protocol_token_fee, user_key, vault_program, token_program] =
305
306pub fn wrap(signer: Pubkey, use_liquidity: bool, amount: u64) -> Instruction {
307    let config_address = config_pda().0;
308    let treasury_address = TREASURY_ADDRESS;
309    let treasury_sol_address = get_associated_token_address(&treasury_address, &SOL_MINT);
310    let data = Wrap {
311        use_liquidity: if use_liquidity { 1 } else { 0 },
312        amount: amount.to_le_bytes(),
313    }
314    .to_bytes();
315    Instruction {
316        program_id: crate::ID,
317        accounts: vec![
318            AccountMeta::new(signer, true),
319            AccountMeta::new_readonly(config_address, false),
320            AccountMeta::new(treasury_address, false),
321            AccountMeta::new(treasury_sol_address, false),
322            AccountMeta::new_readonly(solana_program::system_program::ID, false),
323        ],
324        data,
325    }
326}
327
328pub fn buyback(signer: Pubkey, swap_accounts: &[AccountMeta], swap_data: &[u8]) -> Instruction {
329    let board_address = board_pda().0;
330    let mint_address = MINT_ADDRESS;
331    let treasury_address = TREASURY_ADDRESS;
332    let treasury_oil_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
333    let treasury_sol_address = get_associated_token_address(&treasury_address, &SOL_MINT);
334    let mut accounts = vec![
335        AccountMeta::new(signer, true),
336        AccountMeta::new(board_address, false),
337        AccountMeta::new(mint_address, false),
338        AccountMeta::new(treasury_address, false),
339        AccountMeta::new(treasury_oil_address, false),
340        AccountMeta::new(treasury_sol_address, false),
341        AccountMeta::new_readonly(spl_token::ID, false),
342        AccountMeta::new_readonly(crate::ID, false),
343    ];
344    for account in swap_accounts.iter() {
345        let mut acc_clone = account.clone();
346        acc_clone.is_signer = false;
347        accounts.push(acc_clone);
348    }
349    let mut data = Buyback {}.to_bytes();
350    data.extend_from_slice(swap_data);
351    Instruction {
352        program_id: crate::ID,
353        accounts,
354        data,
355    }
356}
357
358pub fn barrel(signer: Pubkey, amount: u64) -> Instruction {
359    let board_address = board_pda().0;
360    let mint_address = MINT_ADDRESS;
361    let treasury_address = TREASURY_ADDRESS;
362    let sender_oil_address = get_associated_token_address(&signer, &MINT_ADDRESS);
363    let treasury_oil_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
364    let data = Barrel {
365        amount: amount.to_le_bytes(),
366    }
367    .to_bytes();
368    Instruction {
369        program_id: crate::ID,
370        accounts: vec![
371            AccountMeta::new(signer, true),
372            AccountMeta::new(sender_oil_address, false),
373            AccountMeta::new(board_address, false),
374            AccountMeta::new(mint_address, false),
375            AccountMeta::new(treasury_address, false),
376            AccountMeta::new(treasury_oil_address, false),
377            AccountMeta::new_readonly(spl_token::ID, false),
378            AccountMeta::new_readonly(crate::ID, false),
379        ],
380        data,
381    }
382}
383
384
385// let [signer_info, board_info, config_info, fee_collector_info, mint_info, round_info, round_next_info, top_miner_info, treasury_info, treasury_tokens_info, system_program, token_program, oil_program, slot_hashes_sysvar] =
386
387pub fn reset(
388    signer: Pubkey,
389    fee_collector: Pubkey,
390    round_id: u64,
391    top_miner: Pubkey,
392    var_address: Pubkey,
393) -> Instruction {
394    reset_with_miners(signer, fee_collector, round_id, top_miner, var_address, &[])
395}
396
397pub fn reset_with_miners(
398    signer: Pubkey,
399    fee_collector: Pubkey,
400    round_id: u64,
401    top_miner: Pubkey,
402    var_address: Pubkey,
403    miner_accounts: &[Pubkey],
404) -> Instruction {
405    let board_address = board_pda().0;
406    let config_address = config_pda().0;
407    let mint_address = MINT_ADDRESS;
408    let round_address = round_pda(round_id).0;
409    let round_next_address = round_pda(round_id + 1).0;
410    let top_miner_address = miner_pda(top_miner).0;
411    let treasury_address = TREASURY_ADDRESS;
412    let treasury_tokens_address = treasury_tokens_address();
413    let pool_address = pool_pda().0;
414    let mint_authority_address = oil_mint_api::state::authority_pda().0;
415    let mut reset_instruction = Instruction {
416        program_id: crate::ID,
417        accounts: vec![
418            AccountMeta::new(signer, true),
419            AccountMeta::new(board_address, false),
420            AccountMeta::new(config_address, false),
421            AccountMeta::new(fee_collector, false),
422            AccountMeta::new(mint_address, false),
423            AccountMeta::new(round_address, false),
424            AccountMeta::new(round_next_address, false),
425            AccountMeta::new(top_miner_address, false),
426            AccountMeta::new(treasury_address, false),
427            AccountMeta::new(pool_address, false),
428            AccountMeta::new(treasury_tokens_address, false),
429            AccountMeta::new_readonly(system_program::ID, false),
430            AccountMeta::new_readonly(spl_token::ID, false),
431            AccountMeta::new_readonly(crate::ID, false),
432            AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
433            AccountMeta::new_readonly(SOL_MINT, false),
434            // Entropy accounts (these are in "other_accounts" after the split)
435            AccountMeta::new(var_address, false),
436            AccountMeta::new_readonly(entropy_rng_api::ID, false),
437            // Mint accounts.
438            AccountMeta::new(mint_authority_address, false),
439            AccountMeta::new_readonly(oil_mint_api::ID, false),
440        ],
441        data: Reset {}.to_bytes(),
442    };
443    
444    // Add miner accounts for seeker rewards (optional)
445    for miner_pubkey in miner_accounts {
446        reset_instruction.accounts.push(AccountMeta::new(
447            miner_pda(*miner_pubkey).0,
448            false,
449        ));
450    }
451    
452    reset_instruction
453}
454    
455// let [signer_info, automation_info, board_info, miner_info, round_info, treasury_info, system_program] =
456
457pub fn checkpoint(signer: Pubkey, authority: Pubkey, round_id: u64) -> Instruction {
458    let miner_address = miner_pda(authority).0;
459    let board_address = board_pda().0;
460    let config_address = config_pda().0;
461    let round_address = round_pda(round_id).0;
462    let treasury_address = TREASURY_ADDRESS;
463    Instruction {
464        program_id: crate::ID,
465        accounts: vec![
466            AccountMeta::new(signer, true), // signer (used as authority by program)
467            AccountMeta::new(board_address, false),
468            AccountMeta::new(config_address, false), // config (needed for premine check)
469            AccountMeta::new(miner_address, false),
470            AccountMeta::new(round_address, false),
471            AccountMeta::new(treasury_address, false),
472            AccountMeta::new_readonly(system_program::ID, false),
473        ],
474        data: Checkpoint {}.to_bytes(),
475    }
476}
477
478pub fn set_admin(signer: Pubkey, admin: Pubkey) -> Instruction {
479    let config_address = config_pda().0;
480    Instruction {
481        program_id: crate::ID,
482        accounts: vec![
483            AccountMeta::new(signer, true),
484            AccountMeta::new(config_address, false),
485            AccountMeta::new_readonly(system_program::ID, false),
486        ],
487        data: SetAdmin {
488            admin: admin.to_bytes(),
489        }
490        .to_bytes(),
491    }
492}
493
494pub fn set_admin_fee(signer: Pubkey, admin_fee: u64) -> Instruction {
495    let config_address = config_pda().0;
496    Instruction {
497        program_id: crate::ID,
498        accounts: vec![
499            AccountMeta::new(signer, true),
500            AccountMeta::new(config_address, false),
501            AccountMeta::new_readonly(system_program::ID, false),
502        ],
503        data: SetAdminFee {
504            admin_fee: admin_fee.to_le_bytes(),
505        }
506        .to_bytes(),
507    }
508}
509
510pub fn set_fee_collector(signer: Pubkey, fee_collector: Pubkey) -> Instruction {
511    let config_address = config_pda().0;
512    Instruction {
513        program_id: crate::ID,
514        accounts: vec![
515            AccountMeta::new(signer, true),
516            AccountMeta::new(config_address, false),
517            AccountMeta::new_readonly(system_program::ID, false),
518        ],
519        data: SetFeeCollector {
520            fee_collector: fee_collector.to_bytes(),
521        }
522        .to_bytes(),
523    }
524}
525
526/// Sets the TGE (Token Generation Event) timestamp.
527/// If current time < tge_timestamp, pre-mine is active.
528/// Set to 0 to disable pre-mine.
529/// Admin-only instruction.
530pub fn set_tge_timestamp(signer: Pubkey, tge_timestamp: i64) -> Instruction {
531    let config_address = config_pda().0;
532    Instruction {
533        program_id: crate::ID,
534        accounts: vec![
535            AccountMeta::new(signer, true),
536            AccountMeta::new(config_address, false),
537            AccountMeta::new_readonly(system_program::ID, false),
538        ],
539        data: SetTgeTimestamp {
540            tge_timestamp: tge_timestamp.to_le_bytes(),
541        }
542        .to_bytes(),
543    }
544}
545
546pub fn set_auction(
547    signer: Pubkey,
548    halving_period_seconds: u64,
549    last_halving_time: u64,
550    base_mining_rates: [u64; 4],
551    auction_duration_seconds: u64,
552    starting_prices: [u64; 4],
553    _well_id: u64, // Kept for backwards compatibility, but not used (always updates auction only)
554) -> Instruction {
555    let config_address = config_pda().0;
556    let auction_address = auction_pda().0;
557    
558    Instruction {
559        program_id: crate::ID,
560        accounts: vec![
561            AccountMeta::new(signer, true),
562            AccountMeta::new_readonly(config_address, false),
563            AccountMeta::new(auction_address, false),
564        ],
565        data: SetAuction {
566            halving_period_seconds: halving_period_seconds.to_le_bytes(),
567            last_halving_time: last_halving_time.to_le_bytes(),
568            base_mining_rates: [
569                base_mining_rates[0].to_le_bytes(),
570                base_mining_rates[1].to_le_bytes(),
571                base_mining_rates[2].to_le_bytes(),
572                base_mining_rates[3].to_le_bytes(),
573            ],
574            auction_duration_seconds: auction_duration_seconds.to_le_bytes(),
575            starting_prices: [
576                starting_prices[0].to_le_bytes(),
577                starting_prices[1].to_le_bytes(),
578                starting_prices[2].to_le_bytes(),
579                starting_prices[3].to_le_bytes(),
580            ],
581            well_id: 4u64.to_le_bytes(), // Always use 4 to indicate auction-only update
582        }
583        .to_bytes(),
584    }
585}
586
587// let [signer_info, mint_info, sender_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] =
588
589pub fn deposit(signer: Pubkey, authority: Pubkey, amount: u64, lock_duration_days: u64, stake_id: u64) -> Instruction {
590    let mint_address = MINT_ADDRESS;
591    let stake_address = stake_pda_with_id(authority, stake_id).0; // Derive from authority, not signer
592    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
593    let sender_address = get_associated_token_address(&authority, &MINT_ADDRESS); // Authority's ATA
594    let pool_address = pool_pda().0;
595    let pool_tokens_address = pool_tokens_address();
596    let miner_address = miner_pda(authority).0; // Derive from authority
597    Instruction {
598        program_id: crate::ID,
599        accounts: vec![
600            AccountMeta::new(signer, true), // payer (session payer or regular wallet, pays fees)
601            AccountMeta::new(authority, true), // authority (user's wallet, signs token transfer and used for PDA derivation)
602            AccountMeta::new(mint_address, false),
603            AccountMeta::new(sender_address, false),
604            AccountMeta::new(stake_address, false),
605            AccountMeta::new(stake_tokens_address, false),
606            AccountMeta::new(pool_address, false),
607            AccountMeta::new(pool_tokens_address, false),
608            AccountMeta::new(miner_address, false),
609            AccountMeta::new_readonly(system_program::ID, false),
610            AccountMeta::new_readonly(spl_token::ID, false),
611            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
612        ],
613        data: Deposit {
614            amount: amount.to_le_bytes(),
615            lock_duration_days: lock_duration_days.to_le_bytes(),
616            stake_id: stake_id.to_le_bytes(),
617        }
618        .to_bytes(),
619    }
620}
621
622// let [signer_info, mint_info, recipient_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] =
623
624pub fn withdraw(signer: Pubkey, authority: Pubkey, amount: u64, stake_id: u64) -> Instruction {
625    let stake_address = stake_pda_with_id(authority, stake_id).0; // Derive from authority, not signer
626    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
627    let mint_address = MINT_ADDRESS;
628    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS); // Authority's ATA
629    let pool_address = pool_pda().0;
630    let pool_tokens_address = pool_tokens_address();
631    let miner_address = miner_pda(authority).0; // Derive from authority
632    let treasury_address = treasury_pda().0;
633    let treasury_tokens_address = treasury_tokens_address();
634    Instruction {
635        program_id: crate::ID,
636        accounts: vec![
637            AccountMeta::new(signer, true), // payer (session payer or regular wallet)
638            AccountMeta::new(authority, false), // authority (user's wallet, for PDA derivation)
639            AccountMeta::new(mint_address, false),
640            AccountMeta::new(recipient_address, false),
641            AccountMeta::new(stake_address, false),
642            AccountMeta::new(stake_tokens_address, false),
643            AccountMeta::new(pool_address, false),
644            AccountMeta::new(pool_tokens_address, false),
645            AccountMeta::new(miner_address, false),
646            AccountMeta::new(treasury_address, false), // Treasury account (writable, signed by PDA)
647            AccountMeta::new(treasury_tokens_address, false), // Treasury OIL token account (writable, signed by PDA)
648            AccountMeta::new_readonly(system_program::ID, false),
649            AccountMeta::new_readonly(spl_token::ID, false),
650            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
651        ],
652        data: Withdraw {
653            amount: amount.to_le_bytes(),
654            stake_id: stake_id.to_le_bytes(),
655        }
656        .to_bytes(),
657    }
658}
659
660// let [signer_info, automation_info, miner_info, system_program] = accounts else {
661
662/// Reload SOL from miner account to automation balance with single-tier referral system.
663/// 
664/// If the miner has a referrer, 1.0% of the claim goes to the referrer.
665/// 
666/// Account structure:
667/// - Base: signer, automation, miner, system_program
668/// - If miner has referrer (required): [miner_referrer, referral_referrer]
669pub fn reload_sol(
670    signer: Pubkey,
671    authority: Pubkey,
672    referrer_miner: Option<Pubkey>,
673    referrer_referral: Option<Pubkey>,
674) -> Instruction {
675    let automation_address = automation_pda(authority).0;
676    let miner_address = miner_pda(authority).0;
677    
678    let mut accounts = vec![
679        AccountMeta::new(signer, true),
680        AccountMeta::new(automation_address, false),
681        AccountMeta::new(miner_address, false),
682        AccountMeta::new_readonly(system_program::ID, false),
683    ];
684    
685    // Add referral accounts if provided (required when miner has referrer)
686    if let (Some(miner_ref), Some(referral_ref)) = (referrer_miner, referrer_referral) {
687        accounts.push(AccountMeta::new(miner_ref, false));
688        accounts.push(AccountMeta::new(referral_ref, false));
689    }
690    
691    Instruction {
692        program_id: crate::ID,
693        accounts,
694        data: ReloadSOL {}.to_bytes(),
695    }
696}
697
698// let [signer_info, mint_info, recipient_info, stake_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] =
699
700/// Claim SOL yield from staking. Stakers earn SOL rewards (2% of round winnings), not OIL.
701pub fn claim_yield(signer: Pubkey, amount: u64, stake_id: u64) -> Instruction {
702    let stake_address = stake_pda_with_id(signer, stake_id).0;
703    let pool_address = pool_pda().0;
704    Instruction {
705        program_id: crate::ID,
706        accounts: vec![
707            AccountMeta::new(signer, true), // signer and writable for receiving SOL
708            AccountMeta::new(stake_address, false),
709            AccountMeta::new(pool_address, false),
710            AccountMeta::new_readonly(system_program::ID, false),
711        ],
712        data: ClaimYield {
713            amount: amount.to_le_bytes(),
714        }
715        .to_bytes(),
716    }
717}
718
719pub fn new_var(
720    signer: Pubkey,
721    provider: Pubkey,
722    id: u64,
723    commit: [u8; 32],
724    samples: u64,
725) -> Instruction {
726    let board_address = board_pda().0;
727    let config_address = config_pda().0;
728    let var_address = entropy_rng_api::state::var_pda(board_address, id).0;
729    Instruction {
730        program_id: crate::ID,
731        accounts: vec![
732            AccountMeta::new(signer, true),
733            AccountMeta::new(board_address, false),
734            AccountMeta::new(config_address, false),
735            AccountMeta::new(provider, false),
736            AccountMeta::new(var_address, false),
737            AccountMeta::new_readonly(system_program::ID, false),
738            AccountMeta::new_readonly(entropy_rng_api::ID, false),
739        ],
740        data: NewVar {
741            id: id.to_le_bytes(),
742            commit: commit,
743            samples: samples.to_le_bytes(),
744        }
745        .to_bytes(),
746    }
747}
748
749pub fn set_swap_program(signer: Pubkey, new_program: Pubkey) -> Instruction {
750    let config_address = config_pda().0;
751    Instruction {
752        program_id: crate::ID,
753        accounts: vec![
754            AccountMeta::new(signer, true),
755            AccountMeta::new(config_address, false),
756            AccountMeta::new_readonly(new_program, false),
757        ],
758        data: SetSwapProgram {}.to_bytes(),
759    }
760}
761
762pub fn set_var_address(signer: Pubkey, new_var_address: Pubkey) -> Instruction {
763    let board_address = board_pda().0;
764    let config_address = config_pda().0;
765    Instruction {
766        program_id: crate::ID,
767        accounts: vec![
768            AccountMeta::new(signer, true),
769            AccountMeta::new(board_address, false),
770            AccountMeta::new(config_address, false),
771            AccountMeta::new(new_var_address, false),
772        ],
773        data: SetVarAddress {}.to_bytes(),
774    }
775}
776
777/// Migrate: Extend Treasury struct with liquidity field.
778/// This migration ensures the Treasury account has the new liquidity field available.
779/// Must be called by the admin.
780/// Accounts: signer, config, treasury, system_program
781pub fn migrate(signer: Pubkey) -> Instruction {
782    let config_address = config_pda().0;
783    let treasury_address = treasury_pda().0;
784    Instruction {
785        program_id: crate::ID,
786        accounts: vec![
787            AccountMeta::new(signer, true),
788            AccountMeta::new(config_address, false),
789            AccountMeta::new(treasury_address, false),
790            AccountMeta::new_readonly(system_program::ID, false),
791        ],
792        data: Migrate {}.to_bytes(),
793    }
794}
795
796/// Create a referral account to become a referrer.
797pub fn create_referral(signer: Pubkey) -> Instruction {
798    let referral_address = referral_pda(signer).0;
799    Instruction {
800        program_id: crate::ID,
801        accounts: vec![
802            AccountMeta::new(signer, true),
803            AccountMeta::new(referral_address, false),
804            AccountMeta::new_readonly(system_program::ID, false),
805        ],
806        data: CreateReferral {}.to_bytes(),
807    }
808}
809
810/// Creates a Whitelist account for a shared access code.
811/// Admin-only instruction.
812/// Accounts: signer (admin), config, whitelist, system_program
813pub fn create_whitelist(
814    signer: Pubkey,
815    code_hash: [u8; 32],
816) -> Instruction {
817    let config_address = config_pda().0;
818    let (whitelist_address, _) = Whitelist::pda(code_hash);
819    Instruction {
820        program_id: crate::ID,
821        accounts: vec![
822            AccountMeta::new(signer, true), // signer (admin)
823            AccountMeta::new_readonly(config_address, false), // config
824            AccountMeta::new(whitelist_address, false), // whitelist
825            AccountMeta::new_readonly(system_program::ID, false), // system_program
826        ],
827        data: CreateWhitelist {
828            code_hash,
829        }
830        .to_bytes(),
831    }
832}
833
834/// Claim pending referral rewards (both SOL and OIL).
835/// 
836/// Account structure (for Fogo sessions):
837/// - Base: signer (payer), authority (user's wallet), referral, referral_tokens, mint, recipient, system_program, token_program, associated_token_program
838pub fn claim_referral(signer: Pubkey, authority: Pubkey) -> Instruction {
839    let referral_address = referral_pda(authority).0;
840    let referral_oil_address = get_associated_token_address(&referral_address, &MINT_ADDRESS);
841    let recipient_oil_address = get_associated_token_address(&authority, &MINT_ADDRESS);
842    Instruction {
843        program_id: crate::ID,
844        accounts: vec![
845            AccountMeta::new(signer, true), // 0: signer (payer)
846            AccountMeta::new(authority, false), // 1: authority (user's wallet, receives SOL)
847            AccountMeta::new(referral_address, false), // 2: referral
848            AccountMeta::new(referral_oil_address, false), // 3: referral_tokens (Referral account's OIL ATA)
849            AccountMeta::new(MINT_ADDRESS, false), // 4: mint
850            AccountMeta::new(recipient_oil_address, false), // 5: recipient (Recipient's OIL ATA - authority's wallet)
851            AccountMeta::new_readonly(system_program::ID, false), // 6: system_program
852            AccountMeta::new_readonly(spl_token::ID, false), // 7: token_program
853            AccountMeta::new_readonly(spl_associated_token_account::ID, false), // 8: associated_token_program
854        ],
855        data: ClaimReferral {}.to_bytes(),
856    }
857}
858
859/// Direct solo bid on an auction well (seize ownership).
860/// The bid amount is calculated on-chain as current_price + 1 lamport.
861/// User must have enough SOL in their wallet to cover the bid.
862/// 
863/// Account structure:
864/// - Base: signer, authority, program_signer (optional), payer (optional), well, auction, treasury, treasury_tokens, mint, mint_authority, mint_program, staking_pool, fee_collector, config, token_program, system_program, oil_program
865/// - If previous owner exists (optional): [previous_owner_miner, previous_owner]
866/// - If referrer is provided (optional): [referral]
867pub fn place_bid(
868    signer: Pubkey,
869    authority: Pubkey,
870    square_id: u64,
871    fee_collector: Pubkey,
872    previous_owner_miner: Option<Pubkey>, // Previous owner's miner PDA (if previous owner exists)
873    previous_owner: Option<Pubkey>, // Previous owner pubkey (if previous owner exists)
874    referrer: Option<Pubkey>, // Optional referrer pubkey for new miners
875) -> Instruction {
876    let well_address = well_pda(square_id).0;
877    let auction_address = auction_pda().0;
878    let treasury_address = treasury_pda().0;
879    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
880    let staking_pool_address = pool_pda().0;
881    let config_address = config_pda().0;
882    let mint_authority_address = oil_mint_api::state::authority_pda().0;
883    let bidder_miner_address = miner_pda(authority).0;
884    
885    let mut accounts = vec![
886        AccountMeta::new(signer, true), // 0: signer
887        AccountMeta::new(authority, false), // 1: authority
888    ];
889    
890    // Add program_signer and payer for Fogo sessions (these are added by the client, not here)
891    // For now, we'll add placeholders or the client will add them
892    
893    accounts.extend_from_slice(&[
894        AccountMeta::new(well_address, false), // well
895        AccountMeta::new(auction_address, false), // Must be writable for auction_program_log CPI
896        AccountMeta::new(treasury_address, false),
897        AccountMeta::new(treasury_tokens_address, false),
898        AccountMeta::new(MINT_ADDRESS, false),
899        AccountMeta::new(mint_authority_address, false),
900        AccountMeta::new_readonly(oil_mint_api::ID, false),
901        AccountMeta::new(staking_pool_address, false),
902        AccountMeta::new(fee_collector, false),
903        AccountMeta::new_readonly(config_address, false),
904        AccountMeta::new_readonly(spl_token::ID, false),
905        AccountMeta::new_readonly(system_program::ID, false),
906        AccountMeta::new_readonly(crate::ID, false), // oil_program
907        AccountMeta::new(bidder_miner_address, false), // bidder_miner
908    ]);
909    
910    // Add previous owner accounts if provided
911    if let (Some(miner_pubkey), Some(owner_pubkey)) = (previous_owner_miner, previous_owner) {
912        accounts.push(AccountMeta::new(miner_pubkey, false)); // previous_owner_miner
913        accounts.push(AccountMeta::new(owner_pubkey, false)); // previous_owner
914    }
915    
916    // Add referral account if referrer is provided
917    if let Some(referrer_pubkey) = referrer {
918        let referral_address = referral_pda(referrer_pubkey).0;
919        accounts.push(AccountMeta::new(referral_address, false)); // referral
920    }
921    
922    // Note: Wrapped token accounts are added by the client:
923    // - user_wrapped_sol (source)
924    // - treasury_wrapped_sol (temp ATA for all wrapped SOL - will be closed to get native SOL)
925    // - token_program, native_mint, ata_program
926    // The program distributes native SOL from treasury to pool and fee_collector after closing the temp ATA.
927    
928    Instruction {
929        program_id: crate::ID,
930        accounts,
931        data: instruction::PlaceBid {
932            square_id: square_id.to_le_bytes(),
933            referrer: referrer.unwrap_or(Pubkey::default()).to_bytes(),
934        }
935        .to_bytes(),
936    }
937}
938
939/// Claim auction-based OIL rewards
940/// - OIL rewards: from current ownership and previous ownership (pre-minted)
941/// 
942/// Account structure:
943/// - Base: signer, miner, well accounts (one per well in mask), auction pool accounts (optional, one per well), auction, treasury, treasury_tokens, mint, mint_authority, mint_program, recipient, token_program, associated_token_program, system_program, oil_program
944/// - Bid accounts (one per well in mask, required for pool contributors): [bid_0, bid_1, bid_2, bid_3] (must include epoch_id in PDA)
945/// Claim auction-based OIL rewards
946/// 
947/// Account structure:
948/// - Base: signer, miner, well_0, well_1, well_2, well_3, auction, treasury, treasury_tokens, mint, mint_authority, mint_program, recipient, token_program, associated_token_program, system_program, oil_program
949/// - If miner has referrer (required): [miner_referrer, referral_referrer, referral_referrer_oil_ata]
950pub fn claim_auction_oil(
951    signer: Pubkey,
952    well_mask: u8, // Bitmask: bit 0 = well 0, bit 1 = well 1, etc.
953    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
954    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
955    referrer_referral_oil_ata: Option<Pubkey>, // Referrer's referral OIL ATA (if miner has referrer)
956) -> Instruction {
957    let miner_address = miner_pda(signer).0;
958    let well_0_address = well_pda(0).0;
959    let well_1_address = well_pda(1).0;
960    let well_2_address = well_pda(2).0;
961    let well_3_address = well_pda(3).0;
962    let auction_address = auction_pda().0;
963    let treasury_address = treasury_pda().0;
964    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
965    let recipient_address = get_associated_token_address(&signer, &MINT_ADDRESS);
966    let mint_authority_address = oil_mint_api::state::authority_pda().0;
967    
968    let mut accounts = vec![
969        AccountMeta::new(signer, true),
970        AccountMeta::new(miner_address, false),
971        AccountMeta::new(well_0_address, false),
972        AccountMeta::new(well_1_address, false),
973        AccountMeta::new(well_2_address, false),
974        AccountMeta::new(well_3_address, false),
975        AccountMeta::new(auction_address, false),
976        AccountMeta::new(treasury_address, false),
977        AccountMeta::new(treasury_tokens_address, false),
978        AccountMeta::new(MINT_ADDRESS, false),
979        AccountMeta::new(mint_authority_address, false),
980        AccountMeta::new_readonly(oil_mint_api::ID, false),
981        AccountMeta::new(recipient_address, false),
982        AccountMeta::new_readonly(spl_token::ID, false),
983        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
984        AccountMeta::new_readonly(system_program::ID, false),
985        AccountMeta::new_readonly(crate::ID, false),
986    ];
987    
988    // Add referrer accounts if provided (required if miner has referrer)
989    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
990        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
991        accounts.push(AccountMeta::new(miner_pubkey, false));
992        accounts.push(AccountMeta::new(referral_pubkey, false));
993        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
994    }
995    
996    Instruction {
997        program_id: crate::ID,
998        accounts,
999        data: ClaimAuctionOIL {
1000            well_mask,
1001        }
1002        .to_bytes(),
1003    }
1004}
1005
1006/// Claim auction-based SOL rewards
1007/// 
1008/// Account structure:
1009/// - Base: signer (writable), miner, treasury, auction, system_program, oil_program
1010/// - If miner has referrer (required): [miner_referrer, referral_referrer]
1011pub fn claim_auction_sol(
1012    signer: Pubkey,
1013    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
1014    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
1015) -> Instruction {
1016    let miner_address = miner_pda(signer).0;
1017    let (auction_address, _) = auction_pda();
1018    let treasury_address = treasury_pda().0;
1019    
1020    let mut accounts = vec![
1021        AccountMeta::new(signer, true), // signer and writable for receiving SOL
1022        AccountMeta::new(miner_address, false),
1023        AccountMeta::new(treasury_address, false),
1024        AccountMeta::new(auction_address, false),
1025        AccountMeta::new_readonly(system_program::ID, false),
1026        AccountMeta::new_readonly(crate::ID, false),
1027    ];
1028    
1029    // Add referrer accounts if provided (required if miner has referrer)
1030    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
1031        accounts.push(AccountMeta::new(miner_pubkey, false));
1032        accounts.push(AccountMeta::new(referral_pubkey, false));
1033    }
1034    
1035    Instruction {
1036        program_id: crate::ID,
1037        accounts,
1038        data: ClaimAuctionSOL {
1039            _reserved: 0,
1040        }
1041        .to_bytes(),
1042    }
1043}
1044
1045// ============================================================================
1046// FOGO Session SDK Functions
1047// ============================================================================
1048
1049pub fn checkpoint_with_session(
1050    signer: Pubkey,
1051    authority: Pubkey,
1052    program_signer: Pubkey,
1053    round_id: u64,
1054) -> Instruction {
1055    let miner_address = miner_pda(authority).0;
1056    let board_address = board_pda().0;
1057    let config_address = config_pda().0;
1058    let round_address = round_pda(round_id).0;
1059    let treasury_address = TREASURY_ADDRESS;
1060    
1061    // Manually construct instruction data with CheckpointWithSession discriminator (52)
1062    // Checkpoint is an empty struct, so we just need the discriminator byte
1063    let data = vec![52u8]; // CheckpointWithSession = 52
1064    
1065    Instruction {
1066        program_id: crate::ID,
1067        accounts: vec![
1068            AccountMeta::new(signer, true), // signer (session account)
1069            AccountMeta::new(authority, false), // authority (user's wallet)
1070            AccountMeta::new_readonly(program_signer, false), // program_signer
1071            AccountMeta::new(board_address, false),
1072            AccountMeta::new(config_address, false), // config (needed for premine check)
1073            AccountMeta::new(miner_address, false),
1074            AccountMeta::new(round_address, false),
1075            AccountMeta::new(treasury_address, false),
1076            AccountMeta::new_readonly(system_program::ID, false),
1077        ],
1078        data,
1079    }
1080}
1081
1082pub fn deploy_with_session(
1083    signer: Pubkey,
1084    authority: Pubkey,
1085    program_signer: Pubkey,
1086    payer: Pubkey,
1087    amount: u64,
1088    round_id: u64,
1089    squares: [bool; 25],
1090    referrer: Option<Pubkey>,
1091    pooled: bool,
1092) -> Instruction {
1093    let automation_address = automation_pda(authority).0;
1094    let board_address = board_pda().0;
1095    let miner_address = miner_pda(authority).0;
1096    let round_address = round_pda(round_id).0;
1097    let entropy_var_address = entropy_rng_api::state::var_pda(board_address, 0).0;
1098
1099    let mut mask: u32 = 0;
1100    for (i, &square) in squares.iter().enumerate() {
1101        if square {
1102            mask |= 1 << i;
1103        }
1104    }
1105    
1106    let referrer_pubkey = referrer.unwrap_or(Pubkey::default());
1107    // Match program logic: has_referrer = referrer != Pubkey::default() && referrer != authority
1108    let has_referrer = referrer_pubkey != Pubkey::default() && referrer_pubkey != authority;
1109    let user_wrapped_sol_ata = get_associated_token_address(&authority, &SOL_MINT);
1110    let round_wrapped_sol_ata = get_associated_token_address(&round_address, &SOL_MINT);
1111
1112    let mut accounts = vec![
1113        AccountMeta::new(signer, true),
1114        AccountMeta::new(authority, false),
1115        AccountMeta::new_readonly(program_signer, false),
1116        AccountMeta::new(payer, false),
1117        AccountMeta::new(automation_address, false),
1118        AccountMeta::new(board_address, false),
1119        AccountMeta::new(miner_address, false),
1120        AccountMeta::new(round_address, false),
1121        AccountMeta::new_readonly(system_program::ID, false),
1122        AccountMeta::new_readonly(crate::ID, false),
1123        AccountMeta::new(user_wrapped_sol_ata, false),
1124        AccountMeta::new(round_wrapped_sol_ata, false),
1125        AccountMeta::new_readonly(spl_token::ID, false),
1126        AccountMeta::new_readonly(SOL_MINT, false),
1127        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1128    ];
1129    
1130    if has_referrer {
1131        let referral_address = referral_pda(referrer_pubkey).0;
1132        accounts.push(AccountMeta::new(referral_address, false));
1133    }
1134    
1135    accounts.push(AccountMeta::new(entropy_var_address, false));
1136    accounts.push(AccountMeta::new_readonly(entropy_rng_api::ID, false));
1137
1138    Instruction {
1139        program_id: crate::ID,
1140        accounts,
1141        data: Deploy {
1142            amount: amount.to_le_bytes(),
1143            squares: mask.to_le_bytes(),
1144            referrer: referrer_pubkey.to_bytes(),
1145            pooled: if pooled { 1 } else { 0 },
1146        }
1147        .to_bytes(),
1148    }
1149}
1150
1151pub fn automate_with_session(
1152    signer: Pubkey,
1153    authority: Pubkey,
1154    program_signer: Pubkey,
1155    payer: Pubkey,
1156    amount: u64,
1157    deposit: u64,
1158    executor: Pubkey,
1159    fee: u64,
1160    mask: u64,
1161    strategy: u8,
1162    reload: bool,
1163    referrer: Option<Pubkey>,
1164    pooled: bool,
1165    is_new_miner: bool,
1166) -> Instruction {
1167    let automation_address = automation_pda(authority).0;
1168    let miner_address = miner_pda(authority).0;
1169    let referrer_pk = referrer.unwrap_or(Pubkey::default());
1170    let user_wrapped_sol_ata = get_associated_token_address(&authority, &SOL_MINT);
1171    let automation_wrapped_sol_ata = get_associated_token_address(&automation_address, &SOL_MINT);
1172    
1173    let mut accounts = vec![
1174        AccountMeta::new(signer, true),
1175        AccountMeta::new(authority, false),
1176        AccountMeta::new_readonly(program_signer, false),
1177        AccountMeta::new(payer, false),
1178        AccountMeta::new(automation_address, false),
1179        AccountMeta::new(executor, false),
1180        AccountMeta::new(miner_address, false),
1181        AccountMeta::new_readonly(system_program::ID, false),
1182        AccountMeta::new_readonly(crate::ID, false),
1183        AccountMeta::new(user_wrapped_sol_ata, false),
1184        AccountMeta::new(automation_wrapped_sol_ata, false),
1185        AccountMeta::new_readonly(spl_token::ID, false),
1186        AccountMeta::new_readonly(SOL_MINT, false),
1187        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1188    ];
1189    
1190    if is_new_miner && referrer.is_some() && referrer_pk != Pubkey::default() {
1191        let referral_address = referral_pda(referrer_pk).0;
1192        accounts.push(AccountMeta::new(referral_address, false));
1193    }
1194    
1195    Instruction {
1196        program_id: crate::ID,
1197        accounts,
1198        data: Automate {
1199            amount: amount.to_le_bytes(),
1200            deposit: deposit.to_le_bytes(),
1201            fee: fee.to_le_bytes(),
1202            mask: mask.to_le_bytes(),
1203            strategy: strategy as u8,
1204            reload: (reload as u64).to_le_bytes(),
1205            referrer: referrer_pk.to_bytes(),
1206            pooled: pooled as u8,
1207        }
1208        .to_bytes(),
1209    }
1210}
1211
1212pub fn place_bid_with_session(
1213    signer: Pubkey,
1214    authority: Pubkey,
1215    program_signer: Pubkey,
1216    payer: Pubkey,
1217    square_id: u64,
1218    fee_collector: Pubkey,
1219    previous_owner_miner: Option<Pubkey>,
1220    previous_owner: Option<Pubkey>,
1221    referrer: Option<Pubkey>,
1222) -> Instruction {
1223    let well_address = well_pda(square_id).0;
1224    let auction_address = auction_pda().0;
1225    let treasury_address = treasury_pda().0;
1226    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
1227    let staking_pool_address = pool_pda().0;
1228    let config_address = config_pda().0;
1229    let mint_authority_address = oil_mint_api::state::authority_pda().0;
1230    let bidder_miner_address = miner_pda(authority).0;
1231    let user_wrapped_sol_ata = get_associated_token_address(&authority, &SOL_MINT);
1232    let treasury_wrapped_sol_ata = get_associated_token_address(&treasury_address, &SOL_MINT);
1233    
1234    let mut accounts = vec![
1235        AccountMeta::new(signer, true),
1236        AccountMeta::new(authority, false),
1237        AccountMeta::new_readonly(program_signer, false),
1238        AccountMeta::new(payer, false),
1239        AccountMeta::new(well_address, false),
1240        AccountMeta::new(auction_address, false),
1241        AccountMeta::new(treasury_address, false),
1242        AccountMeta::new(treasury_tokens_address, false),
1243        AccountMeta::new(MINT_ADDRESS, false),
1244        AccountMeta::new(mint_authority_address, false),
1245        AccountMeta::new_readonly(oil_mint_api::ID, false),
1246        AccountMeta::new(staking_pool_address, false),
1247        AccountMeta::new(fee_collector, false),
1248        AccountMeta::new_readonly(config_address, false),
1249        AccountMeta::new_readonly(spl_token::ID, false),
1250        AccountMeta::new_readonly(system_program::ID, false),
1251        AccountMeta::new_readonly(crate::ID, false),
1252        AccountMeta::new(bidder_miner_address, false),
1253    ];
1254    
1255    if let (Some(miner_pubkey), Some(owner_pubkey)) = (previous_owner_miner, previous_owner) {
1256        accounts.push(AccountMeta::new(miner_pubkey, false));
1257        accounts.push(AccountMeta::new(owner_pubkey, false));
1258    }
1259    
1260    if let Some(referrer_pubkey) = referrer {
1261        let referral_address = referral_pda(referrer_pubkey).0;
1262        accounts.push(AccountMeta::new(referral_address, false));
1263    }
1264    
1265    accounts.extend_from_slice(&[
1266        AccountMeta::new(user_wrapped_sol_ata, false),
1267        AccountMeta::new(treasury_wrapped_sol_ata, false),
1268        AccountMeta::new_readonly(spl_token::ID, false),
1269        AccountMeta::new_readonly(SOL_MINT, false),
1270        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1271    ]);
1272    
1273    Instruction {
1274        program_id: crate::ID,
1275        accounts,
1276        data: instruction::PlaceBid {
1277            square_id: square_id.to_le_bytes(),
1278            referrer: referrer.unwrap_or(Pubkey::default()).to_bytes(),
1279        }
1280        .to_bytes(),
1281    }
1282}
1283
1284pub fn claim_auction_oil_with_session(
1285    signer: Pubkey,
1286    authority: Pubkey,
1287    program_signer: Pubkey,
1288    payer: Pubkey,
1289    well_mask: u8,
1290    referrer_miner: Option<Pubkey>,
1291    referrer_referral: Option<Pubkey>,
1292    referrer_referral_oil_ata: Option<Pubkey>,
1293) -> Instruction {
1294    let miner_address = miner_pda(authority).0;
1295    let well_0_address = well_pda(0).0;
1296    let well_1_address = well_pda(1).0;
1297    let well_2_address = well_pda(2).0;
1298    let well_3_address = well_pda(3).0;
1299    let auction_address = auction_pda().0;
1300    let treasury_address = treasury_pda().0;
1301    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
1302    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1303    let mint_authority_address = oil_mint_api::state::authority_pda().0;
1304    
1305    let mut accounts = vec![
1306        AccountMeta::new(signer, true),
1307        AccountMeta::new(authority, false),
1308        AccountMeta::new_readonly(program_signer, false),
1309        AccountMeta::new(payer, false),
1310        AccountMeta::new(miner_address, false),
1311        AccountMeta::new(well_0_address, false),
1312        AccountMeta::new(well_1_address, false),
1313        AccountMeta::new(well_2_address, false),
1314        AccountMeta::new(well_3_address, false),
1315        AccountMeta::new(auction_address, false),
1316        AccountMeta::new(treasury_address, false),
1317        AccountMeta::new(treasury_tokens_address, false),
1318        AccountMeta::new(MINT_ADDRESS, false),
1319        AccountMeta::new(mint_authority_address, false),
1320        AccountMeta::new_readonly(oil_mint_api::ID, false),
1321        AccountMeta::new(recipient_address, false),
1322        AccountMeta::new_readonly(spl_token::ID, false),
1323        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1324        AccountMeta::new_readonly(system_program::ID, false),
1325        AccountMeta::new_readonly(crate::ID, false),
1326    ];
1327    
1328    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
1329        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
1330        accounts.push(AccountMeta::new(miner_pubkey, false));
1331        accounts.push(AccountMeta::new(referral_pubkey, false));
1332        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
1333    }
1334    
1335    Instruction {
1336        program_id: crate::ID,
1337        accounts,
1338        data: ClaimAuctionOIL {
1339            well_mask,
1340        }
1341        .to_bytes(),
1342    }
1343}
1344
1345pub fn claim_auction_sol_with_session(
1346    signer: Pubkey,
1347    authority: Pubkey,
1348    program_signer: Pubkey,
1349    payer: Pubkey,
1350    referrer_miner: Option<Pubkey>,
1351    referrer_referral: Option<Pubkey>,
1352) -> Instruction {
1353    let miner_address = miner_pda(authority).0;
1354    let (auction_address, _) = auction_pda();
1355    let treasury_address = treasury_pda().0;
1356    
1357    let mut accounts = vec![
1358        AccountMeta::new(signer, true),
1359        AccountMeta::new(authority, false),
1360        AccountMeta::new_readonly(program_signer, false),
1361        AccountMeta::new(payer, false),
1362        AccountMeta::new(miner_address, false),
1363        AccountMeta::new(treasury_address, false),
1364        AccountMeta::new(auction_address, false),
1365        AccountMeta::new_readonly(system_program::ID, false),
1366        AccountMeta::new_readonly(crate::ID, false),
1367    ];
1368    
1369    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
1370        accounts.push(AccountMeta::new(miner_pubkey, false));
1371        accounts.push(AccountMeta::new(referral_pubkey, false));
1372    }
1373    
1374    Instruction {
1375        program_id: crate::ID,
1376        accounts,
1377        data: ClaimAuctionSOL {
1378            _reserved: 0,
1379        }
1380        .to_bytes(),
1381    }
1382}
1383
1384pub fn claim_sol_with_session(
1385    signer: Pubkey,
1386    authority: Pubkey,
1387    program_signer: Pubkey,
1388    payer: Pubkey,
1389    referrer_miner: Option<Pubkey>,
1390    referrer_referral: Option<Pubkey>,
1391) -> Instruction {
1392    let miner_address = miner_pda(authority).0;
1393    
1394    let mut accounts = vec![
1395        AccountMeta::new(signer, true),
1396        AccountMeta::new(authority, false),
1397        AccountMeta::new_readonly(program_signer, false),
1398        AccountMeta::new(payer, false),
1399        AccountMeta::new(miner_address, false),
1400        AccountMeta::new_readonly(system_program::ID, false),
1401    ];
1402    
1403    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
1404        accounts.push(AccountMeta::new(miner_pubkey, false));
1405        accounts.push(AccountMeta::new(referral_pubkey, false));
1406    }
1407    
1408    Instruction {
1409        program_id: crate::ID,
1410        accounts,
1411        data: ClaimSOL {}.to_bytes(),
1412    }
1413}
1414
1415pub fn claim_oil_with_session(
1416    signer: Pubkey,
1417    authority: Pubkey,
1418    program_signer: Pubkey,
1419    payer: Pubkey,
1420    referrer_miner: Option<Pubkey>,
1421    referrer_referral: Option<Pubkey>,
1422    referrer_referral_oil_ata: Option<Pubkey>,
1423) -> Instruction {
1424    let miner_address = miner_pda(authority).0;
1425    let treasury_address = treasury_pda().0;
1426    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
1427    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1428    
1429    let mut accounts = vec![
1430        AccountMeta::new(signer, true),
1431        AccountMeta::new(authority, false),
1432        AccountMeta::new_readonly(program_signer, false),
1433        AccountMeta::new(payer, false),
1434        AccountMeta::new(miner_address, false),
1435        AccountMeta::new(MINT_ADDRESS, false),
1436        AccountMeta::new(recipient_address, false),
1437        AccountMeta::new(treasury_address, false),
1438        AccountMeta::new(treasury_tokens_address, false),
1439        AccountMeta::new_readonly(system_program::ID, false),
1440        AccountMeta::new_readonly(spl_token::ID, false),
1441        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1442    ];
1443    
1444    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
1445        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
1446        accounts.push(AccountMeta::new(miner_pubkey, false));
1447        accounts.push(AccountMeta::new(referral_pubkey, false));
1448        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
1449    }
1450    
1451    Instruction {
1452        program_id: crate::ID,
1453        accounts,
1454        data: ClaimOIL {}.to_bytes(),
1455    }
1456}
1457
1458pub fn withdraw_with_session(
1459    signer: Pubkey,
1460    authority: Pubkey,
1461    program_signer: Pubkey,
1462    payer: Pubkey,
1463    amount: u64,
1464    stake_id: u64,
1465) -> Instruction {
1466    let stake_address = stake_pda_with_id(authority, stake_id).0;
1467    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
1468    let mint_address = MINT_ADDRESS;
1469    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1470    let pool_address = pool_pda().0;
1471    let pool_tokens_address = pool_tokens_address();
1472    let miner_address = miner_pda(authority).0;
1473    let treasury_address = treasury_pda().0;
1474    let treasury_tokens_address = treasury_tokens_address();
1475    
1476    Instruction {
1477        program_id: crate::ID,
1478        accounts: vec![
1479            AccountMeta::new(signer, true),
1480            AccountMeta::new(authority, false),
1481            AccountMeta::new_readonly(program_signer, false),
1482            AccountMeta::new(payer, false),
1483            AccountMeta::new(mint_address, false),
1484            AccountMeta::new(recipient_address, false),
1485            AccountMeta::new(stake_address, false),
1486            AccountMeta::new(stake_tokens_address, false),
1487            AccountMeta::new(pool_address, false),
1488            AccountMeta::new(pool_tokens_address, false),
1489            AccountMeta::new(miner_address, false),
1490            AccountMeta::new(treasury_address, false),
1491            AccountMeta::new(treasury_tokens_address, false),
1492            AccountMeta::new_readonly(system_program::ID, false),
1493            AccountMeta::new_readonly(spl_token::ID, false),
1494            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1495        ],
1496        data: Withdraw {
1497            amount: amount.to_le_bytes(),
1498            stake_id: stake_id.to_le_bytes(),
1499        }
1500        .to_bytes(),
1501    }
1502}
1503
1504pub fn deposit_with_session(
1505    signer: Pubkey,
1506    authority: Pubkey,
1507    program_signer: Pubkey,
1508    payer: Pubkey,
1509    amount: u64,
1510    lock_duration_days: u64,
1511    stake_id: u64,
1512) -> Instruction {
1513    let mint_address = MINT_ADDRESS;
1514    let stake_address = stake_pda_with_id(authority, stake_id).0;
1515    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
1516    let sender_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1517    let pool_address = pool_pda().0;
1518    let pool_tokens_address = pool_tokens_address();
1519    let miner_address = miner_pda(authority).0;
1520    
1521    let mut data = Deposit {
1522        amount: amount.to_le_bytes(),
1523        lock_duration_days: lock_duration_days.to_le_bytes(),
1524        stake_id: stake_id.to_le_bytes(),
1525    }
1526    .to_bytes();
1527    data[0] = 48u8; // DepositWithSession = 48
1528    
1529    Instruction {
1530        program_id: crate::ID,
1531        accounts: vec![
1532            AccountMeta::new(signer, true), // 0: signer (session account)
1533            AccountMeta::new(authority, false), // 1: authority (user's wallet)
1534            AccountMeta::new_readonly(program_signer, false), // 2: program_signer
1535            AccountMeta::new(payer, false), // 3: payer (paymaster sponsor)
1536            AccountMeta::new(mint_address, false), // 4: mint
1537            AccountMeta::new(sender_address, false), // 5: sender (authority's OIL ATA)
1538            AccountMeta::new(stake_address, false), // 6: stake
1539            AccountMeta::new(stake_tokens_address, false), // 7: stake_tokens
1540            AccountMeta::new(pool_address, false), // 8: pool
1541            AccountMeta::new(pool_tokens_address, false), // 9: pool_tokens
1542            AccountMeta::new(miner_address, false), // 10: miner
1543            AccountMeta::new_readonly(system_program::ID, false), // 11: system_program
1544            AccountMeta::new_readonly(spl_token::ID, false), // 12: token_program
1545            AccountMeta::new_readonly(spl_associated_token_account::ID, false), // 13: associated_token_program
1546        ],
1547        data,
1548    }
1549}
1550
1551pub fn claim_yield_with_session(
1552    signer: Pubkey,
1553    authority: Pubkey,
1554    program_signer: Pubkey,
1555    amount: u64,
1556    stake_id: u64,
1557) -> Instruction {
1558    let stake_address = stake_pda_with_id(authority, stake_id).0;
1559    let pool_address = pool_pda().0;
1560    
1561    let mut data = ClaimYield {
1562        amount: amount.to_le_bytes(),
1563    }
1564    .to_bytes();
1565    data[0] = 51u8; // ClaimYieldWithSession = 51
1566    
1567    Instruction {
1568        program_id: crate::ID,
1569        accounts: vec![
1570            AccountMeta::new(signer, true), // 0: signer (session account)
1571            AccountMeta::new(authority, true), // 1: authority (user's wallet, writable for receiving SOL)
1572            AccountMeta::new_readonly(program_signer, false), // 2: program_signer
1573            AccountMeta::new(stake_address, false), // 3: stake
1574            AccountMeta::new(pool_address, false), // 4: pool
1575            AccountMeta::new_readonly(system_program::ID, false), // 5: system_program
1576        ],
1577        data,
1578    }
1579}
1580
1581pub fn create_referral_with_session(
1582    signer: Pubkey,
1583    authority: Pubkey,
1584    program_signer: Pubkey,
1585    payer: Pubkey,
1586) -> Instruction {
1587    let referral_address = referral_pda(authority).0;
1588    
1589    // CreateReferralWithSession = 49
1590    let data = vec![49u8];
1591    
1592    Instruction {
1593        program_id: crate::ID,
1594        accounts: vec![
1595            AccountMeta::new(signer, true), // 0: signer (session account)
1596            AccountMeta::new(authority, false), // 1: authority (user's wallet)
1597            AccountMeta::new_readonly(program_signer, false), // 2: program_signer
1598            AccountMeta::new(payer, false), // 3: payer (paymaster sponsor)
1599            AccountMeta::new(referral_address, false), // 4: referral
1600            AccountMeta::new_readonly(system_program::ID, false), // 5: system_program
1601        ],
1602        data,
1603    }
1604}
1605
1606pub fn claim_referral_with_session(
1607    signer: Pubkey,
1608    authority: Pubkey,
1609    program_signer: Pubkey,
1610    payer: Pubkey,
1611) -> Instruction {
1612    let referral_address = referral_pda(authority).0;
1613    let referral_oil_address = get_associated_token_address(&referral_address, &MINT_ADDRESS);
1614    let recipient_oil_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1615    
1616    // ClaimReferralWithSession = 50
1617    let data = vec![50u8];
1618    
1619    Instruction {
1620        program_id: crate::ID,
1621        accounts: vec![
1622            AccountMeta::new(signer, true), // 0: signer (session account)
1623            AccountMeta::new(authority, false), // 1: authority (user's wallet, receives SOL)
1624            AccountMeta::new_readonly(program_signer, false), // 2: program_signer
1625            AccountMeta::new(payer, false), // 3: payer (paymaster sponsor)
1626            AccountMeta::new(referral_address, false), // 4: referral
1627            AccountMeta::new(referral_oil_address, false), // 5: referral_tokens (Referral account's OIL ATA)
1628            AccountMeta::new(MINT_ADDRESS, false), // 6: mint
1629            AccountMeta::new(recipient_oil_address, false), // 7: recipient (Recipient's OIL ATA - authority's wallet)
1630            AccountMeta::new_readonly(system_program::ID, false), // 8: system_program
1631            AccountMeta::new_readonly(spl_token::ID, false), // 9: token_program
1632            AccountMeta::new_readonly(spl_associated_token_account::ID, false), // 10: associated_token_program
1633        ],
1634        data,
1635    }
1636}