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