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
264    // Build accounts list - must match program structure:
265    // Oil accounts: base (8) + optional referral (1) = 8-9
266    // Entropy accounts: var + program = 2 (always exactly 2)
267    let mut accounts = vec![
268        AccountMeta::new(signer, true), // 0: signer
269        AccountMeta::new(authority, false), // 1: authority
270        AccountMeta::new(automation_address, false), // 2: automation
271        AccountMeta::new(board_address, false), // 3: board
272        AccountMeta::new(miner_address, false), // 4: miner
273        AccountMeta::new(round_address, false), // 5: round
274        AccountMeta::new_readonly(system_program::ID, false), // 6: system_program
275        AccountMeta::new_readonly(crate::ID, false), // 7: oil_program
276    ];
277    
278    // Add referral account if referrer is provided (in oil_accounts)
279    if referrer_pubkey != Pubkey::default() {
280        let referral_address = referral_pda(referrer_pubkey).0;
281        accounts.push(AccountMeta::new(referral_address, false)); // referral (optional, in oil_accounts)
282    }
283    
284    // Entropy accounts (always exactly 2, come after all oil_accounts)
285    accounts.push(AccountMeta::new(entropy_var_address, false)); // entropy_var
286    accounts.push(AccountMeta::new_readonly(entropy_rng_api::ID, false)); // entropy_program
287
288    Instruction {
289        program_id: crate::ID,
290        accounts,
291        data: Deploy {
292            amount: amount.to_le_bytes(),
293            squares: mask.to_le_bytes(),
294            referrer: referrer_bytes,
295            pooled: if pooled { 1 } else { 0 },
296        }
297        .to_bytes(),
298    }
299}
300
301
302// 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] =
303
304pub fn wrap(signer: Pubkey, use_liquidity: bool, amount: u64) -> Instruction {
305    let config_address = config_pda().0;
306    let treasury_address = TREASURY_ADDRESS;
307    let treasury_sol_address = get_associated_token_address(&treasury_address, &SOL_MINT);
308    let data = Wrap {
309        use_liquidity: if use_liquidity { 1 } else { 0 },
310        amount: amount.to_le_bytes(),
311    }
312    .to_bytes();
313    Instruction {
314        program_id: crate::ID,
315        accounts: vec![
316            AccountMeta::new(signer, true),
317            AccountMeta::new_readonly(config_address, false),
318            AccountMeta::new(treasury_address, false),
319            AccountMeta::new(treasury_sol_address, false),
320            AccountMeta::new_readonly(solana_program::system_program::ID, false),
321        ],
322        data,
323    }
324}
325
326pub fn buyback(signer: Pubkey, swap_accounts: &[AccountMeta], swap_data: &[u8]) -> Instruction {
327    let board_address = board_pda().0;
328    let mint_address = MINT_ADDRESS;
329    let treasury_address = TREASURY_ADDRESS;
330    let treasury_oil_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
331    let treasury_sol_address = get_associated_token_address(&treasury_address, &SOL_MINT);
332    let mut accounts = vec![
333        AccountMeta::new(signer, true),
334        AccountMeta::new(board_address, false),
335        AccountMeta::new(mint_address, false),
336        AccountMeta::new(treasury_address, false),
337        AccountMeta::new(treasury_oil_address, false),
338        AccountMeta::new(treasury_sol_address, false),
339        AccountMeta::new_readonly(spl_token::ID, false),
340        AccountMeta::new_readonly(crate::ID, false),
341    ];
342    for account in swap_accounts.iter() {
343        let mut acc_clone = account.clone();
344        acc_clone.is_signer = false;
345        accounts.push(acc_clone);
346    }
347    let mut data = Buyback {}.to_bytes();
348    data.extend_from_slice(swap_data);
349    Instruction {
350        program_id: crate::ID,
351        accounts,
352        data,
353    }
354}
355
356pub fn barrel(signer: Pubkey, amount: u64) -> Instruction {
357    let board_address = board_pda().0;
358    let mint_address = MINT_ADDRESS;
359    let treasury_address = TREASURY_ADDRESS;
360    let sender_oil_address = get_associated_token_address(&signer, &MINT_ADDRESS);
361    let treasury_oil_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
362    let data = Barrel {
363        amount: amount.to_le_bytes(),
364    }
365    .to_bytes();
366    Instruction {
367        program_id: crate::ID,
368        accounts: vec![
369            AccountMeta::new(signer, true),
370            AccountMeta::new(sender_oil_address, false),
371            AccountMeta::new(board_address, false),
372            AccountMeta::new(mint_address, false),
373            AccountMeta::new(treasury_address, false),
374            AccountMeta::new(treasury_oil_address, false),
375            AccountMeta::new_readonly(spl_token::ID, false),
376            AccountMeta::new_readonly(crate::ID, false),
377        ],
378        data,
379    }
380}
381
382
383// 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] =
384
385pub fn reset(
386    signer: Pubkey,
387    fee_collector: Pubkey,
388    round_id: u64,
389    top_miner: Pubkey,
390    var_address: Pubkey,
391) -> Instruction {
392    reset_with_miners(signer, fee_collector, round_id, top_miner, var_address, &[])
393}
394
395pub fn reset_with_miners(
396    signer: Pubkey,
397    fee_collector: Pubkey,
398    round_id: u64,
399    top_miner: Pubkey,
400    var_address: Pubkey,
401    miner_accounts: &[Pubkey],
402) -> Instruction {
403    let board_address = board_pda().0;
404    let config_address = config_pda().0;
405    let mint_address = MINT_ADDRESS;
406    let round_address = round_pda(round_id).0;
407    let round_next_address = round_pda(round_id + 1).0;
408    let top_miner_address = miner_pda(top_miner).0;
409    let treasury_address = TREASURY_ADDRESS;
410    let treasury_tokens_address = treasury_tokens_address();
411    let pool_address = pool_pda().0;
412    let mint_authority_address = oil_mint_api::state::authority_pda().0;
413    let mut reset_instruction = Instruction {
414        program_id: crate::ID,
415        accounts: vec![
416            AccountMeta::new(signer, true),
417            AccountMeta::new(board_address, false),
418            AccountMeta::new(config_address, false),
419            AccountMeta::new(fee_collector, false),
420            AccountMeta::new(mint_address, false),
421            AccountMeta::new(round_address, false),
422            AccountMeta::new(round_next_address, false),
423            AccountMeta::new(top_miner_address, false),
424            AccountMeta::new(treasury_address, false),
425            AccountMeta::new(pool_address, false),
426            AccountMeta::new(treasury_tokens_address, false),
427            AccountMeta::new_readonly(system_program::ID, false),
428            AccountMeta::new_readonly(spl_token::ID, false),
429            AccountMeta::new_readonly(crate::ID, false),
430            AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
431            AccountMeta::new_readonly(SOL_MINT, false),
432            // Entropy accounts (these are in "other_accounts" after the split)
433            AccountMeta::new(var_address, false),
434            AccountMeta::new_readonly(entropy_rng_api::ID, false),
435            // Mint accounts.
436            AccountMeta::new(mint_authority_address, false),
437            AccountMeta::new_readonly(oil_mint_api::ID, false),
438        ],
439        data: Reset {}.to_bytes(),
440    };
441    
442    // Add miner accounts for seeker rewards (optional)
443    for miner_pubkey in miner_accounts {
444        reset_instruction.accounts.push(AccountMeta::new(
445            miner_pda(*miner_pubkey).0,
446            false,
447        ));
448    }
449    
450    reset_instruction
451}
452    
453// let [signer_info, automation_info, board_info, miner_info, round_info, treasury_info, system_program] =
454
455pub fn checkpoint(signer: Pubkey, authority: Pubkey, round_id: u64) -> Instruction {
456    let miner_address = miner_pda(authority).0;
457    let board_address = board_pda().0;
458    let config_address = config_pda().0;
459    let round_address = round_pda(round_id).0;
460    let treasury_address = TREASURY_ADDRESS;
461    Instruction {
462        program_id: crate::ID,
463        accounts: vec![
464            AccountMeta::new(signer, true), // payer (session payer or regular wallet, receives bot fee)
465            AccountMeta::new(authority, false), // authority (user's wallet, for PDA derivation - must be writable when combined with deploy)
466            AccountMeta::new(board_address, false),
467            AccountMeta::new(config_address, false), // config (needed for premine check)
468            AccountMeta::new(miner_address, false),
469            AccountMeta::new(round_address, false),
470            AccountMeta::new(treasury_address, false),
471            AccountMeta::new_readonly(system_program::ID, false),
472        ],
473        data: Checkpoint {}.to_bytes(),
474    }
475}
476
477pub fn set_admin(signer: Pubkey, admin: Pubkey) -> Instruction {
478    let config_address = config_pda().0;
479    Instruction {
480        program_id: crate::ID,
481        accounts: vec![
482            AccountMeta::new(signer, true),
483            AccountMeta::new(config_address, false),
484            AccountMeta::new_readonly(system_program::ID, false),
485        ],
486        data: SetAdmin {
487            admin: admin.to_bytes(),
488        }
489        .to_bytes(),
490    }
491}
492
493pub fn set_admin_fee(signer: Pubkey, admin_fee: u64) -> Instruction {
494    let config_address = config_pda().0;
495    Instruction {
496        program_id: crate::ID,
497        accounts: vec![
498            AccountMeta::new(signer, true),
499            AccountMeta::new(config_address, false),
500            AccountMeta::new_readonly(system_program::ID, false),
501        ],
502        data: SetAdminFee {
503            admin_fee: admin_fee.to_le_bytes(),
504        }
505        .to_bytes(),
506    }
507}
508
509pub fn set_fee_collector(signer: Pubkey, fee_collector: Pubkey) -> Instruction {
510    let config_address = config_pda().0;
511    Instruction {
512        program_id: crate::ID,
513        accounts: vec![
514            AccountMeta::new(signer, true),
515            AccountMeta::new(config_address, false),
516            AccountMeta::new_readonly(system_program::ID, false),
517        ],
518        data: SetFeeCollector {
519            fee_collector: fee_collector.to_bytes(),
520        }
521        .to_bytes(),
522    }
523}
524
525/// Sets the TGE (Token Generation Event) timestamp.
526/// If current time < tge_timestamp, pre-mine is active.
527/// Set to 0 to disable pre-mine.
528/// Admin-only instruction.
529pub fn set_tge_timestamp(signer: Pubkey, tge_timestamp: i64) -> Instruction {
530    let config_address = config_pda().0;
531    Instruction {
532        program_id: crate::ID,
533        accounts: vec![
534            AccountMeta::new(signer, true),
535            AccountMeta::new(config_address, false),
536            AccountMeta::new_readonly(system_program::ID, false),
537        ],
538        data: SetTgeTimestamp {
539            tge_timestamp: tge_timestamp.to_le_bytes(),
540        }
541        .to_bytes(),
542    }
543}
544
545pub fn set_auction(
546    signer: Pubkey,
547    halving_period_seconds: u64,
548    last_halving_time: u64,
549    base_mining_rates: [u64; 4],
550    auction_duration_seconds: u64,
551    starting_prices: [u64; 4],
552    _well_id: u64, // Kept for backwards compatibility, but not used (always updates auction only)
553) -> Instruction {
554    let config_address = config_pda().0;
555    let auction_address = auction_pda().0;
556    
557    Instruction {
558        program_id: crate::ID,
559        accounts: vec![
560            AccountMeta::new(signer, true),
561            AccountMeta::new_readonly(config_address, false),
562            AccountMeta::new(auction_address, false),
563        ],
564        data: SetAuction {
565            halving_period_seconds: halving_period_seconds.to_le_bytes(),
566            last_halving_time: last_halving_time.to_le_bytes(),
567            base_mining_rates: [
568                base_mining_rates[0].to_le_bytes(),
569                base_mining_rates[1].to_le_bytes(),
570                base_mining_rates[2].to_le_bytes(),
571                base_mining_rates[3].to_le_bytes(),
572            ],
573            auction_duration_seconds: auction_duration_seconds.to_le_bytes(),
574            starting_prices: [
575                starting_prices[0].to_le_bytes(),
576                starting_prices[1].to_le_bytes(),
577                starting_prices[2].to_le_bytes(),
578                starting_prices[3].to_le_bytes(),
579            ],
580            well_id: 4u64.to_le_bytes(), // Always use 4 to indicate auction-only update
581        }
582        .to_bytes(),
583    }
584}
585
586// let [signer_info, mint_info, sender_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] =
587
588pub fn deposit(signer: Pubkey, authority: Pubkey, amount: u64, lock_duration_days: u64, stake_id: u64) -> Instruction {
589    let mint_address = MINT_ADDRESS;
590    let stake_address = stake_pda_with_id(authority, stake_id).0; // Derive from authority, not signer
591    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
592    let sender_address = get_associated_token_address(&authority, &MINT_ADDRESS); // Authority's ATA
593    let pool_address = pool_pda().0;
594    let pool_tokens_address = pool_tokens_address();
595    let miner_address = miner_pda(authority).0; // Derive from authority
596    Instruction {
597        program_id: crate::ID,
598        accounts: vec![
599            AccountMeta::new(signer, true), // payer (session payer or regular wallet, pays fees)
600            AccountMeta::new(authority, true), // authority (user's wallet, signs token transfer and used for PDA derivation)
601            AccountMeta::new(mint_address, false),
602            AccountMeta::new(sender_address, false),
603            AccountMeta::new(stake_address, false),
604            AccountMeta::new(stake_tokens_address, false),
605            AccountMeta::new(pool_address, false),
606            AccountMeta::new(pool_tokens_address, false),
607            AccountMeta::new(miner_address, false),
608            AccountMeta::new_readonly(system_program::ID, false),
609            AccountMeta::new_readonly(spl_token::ID, false),
610            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
611        ],
612        data: Deposit {
613            amount: amount.to_le_bytes(),
614            lock_duration_days: lock_duration_days.to_le_bytes(),
615            stake_id: stake_id.to_le_bytes(),
616        }
617        .to_bytes(),
618    }
619}
620
621// let [signer_info, mint_info, recipient_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] =
622
623pub fn withdraw(signer: Pubkey, authority: Pubkey, amount: u64, stake_id: u64) -> Instruction {
624    let stake_address = stake_pda_with_id(authority, stake_id).0; // Derive from authority, not signer
625    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
626    let mint_address = MINT_ADDRESS;
627    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS); // Authority's ATA
628    let pool_address = pool_pda().0;
629    let pool_tokens_address = pool_tokens_address();
630    let miner_address = miner_pda(authority).0; // Derive from authority
631    let treasury_address = treasury_pda().0;
632    let treasury_tokens_address = treasury_tokens_address();
633    Instruction {
634        program_id: crate::ID,
635        accounts: vec![
636            AccountMeta::new(signer, true), // payer (session payer or regular wallet)
637            AccountMeta::new(authority, false), // authority (user's wallet, for PDA derivation)
638            AccountMeta::new(mint_address, false),
639            AccountMeta::new(recipient_address, false),
640            AccountMeta::new(stake_address, false),
641            AccountMeta::new(stake_tokens_address, false),
642            AccountMeta::new(pool_address, false),
643            AccountMeta::new(pool_tokens_address, false),
644            AccountMeta::new(miner_address, false),
645            AccountMeta::new(treasury_address, false), // Treasury account (writable, signed by PDA)
646            AccountMeta::new(treasury_tokens_address, false), // Treasury OIL token account (writable, signed by PDA)
647            AccountMeta::new_readonly(system_program::ID, false),
648            AccountMeta::new_readonly(spl_token::ID, false),
649            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
650        ],
651        data: Withdraw {
652            amount: amount.to_le_bytes(),
653            stake_id: stake_id.to_le_bytes(),
654        }
655        .to_bytes(),
656    }
657}
658
659// let [signer_info, automation_info, miner_info, system_program] = accounts else {
660
661/// Reload SOL from miner account to automation balance with single-tier referral system.
662/// 
663/// If the miner has a referrer, 1.0% of the claim goes to the referrer.
664/// 
665/// Account structure:
666/// - Base: signer, automation, miner, system_program
667/// - If miner has referrer (required): [miner_referrer, referral_referrer]
668pub fn reload_sol(
669    signer: Pubkey,
670    authority: Pubkey,
671    referrer_miner: Option<Pubkey>,
672    referrer_referral: Option<Pubkey>,
673) -> Instruction {
674    let automation_address = automation_pda(authority).0;
675    let miner_address = miner_pda(authority).0;
676    
677    let mut accounts = vec![
678        AccountMeta::new(signer, true),
679        AccountMeta::new(automation_address, false),
680        AccountMeta::new(miner_address, false),
681        AccountMeta::new_readonly(system_program::ID, false),
682    ];
683    
684    // Add referral accounts if provided (required when miner has referrer)
685    if let (Some(miner_ref), Some(referral_ref)) = (referrer_miner, referrer_referral) {
686        accounts.push(AccountMeta::new(miner_ref, false));
687        accounts.push(AccountMeta::new(referral_ref, false));
688    }
689    
690    Instruction {
691        program_id: crate::ID,
692        accounts,
693        data: ReloadSOL {}.to_bytes(),
694    }
695}
696
697// let [signer_info, mint_info, recipient_info, stake_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] =
698
699/// Claim SOL yield from staking. Stakers earn SOL rewards (2% of round winnings), not OIL.
700pub fn claim_yield(signer: Pubkey, amount: u64, stake_id: u64) -> Instruction {
701    let stake_address = stake_pda_with_id(signer, stake_id).0;
702    let pool_address = pool_pda().0;
703    Instruction {
704        program_id: crate::ID,
705        accounts: vec![
706            AccountMeta::new(signer, true), // signer and writable for receiving SOL
707            AccountMeta::new(stake_address, false),
708            AccountMeta::new(pool_address, false),
709            AccountMeta::new_readonly(system_program::ID, false),
710        ],
711        data: ClaimYield {
712            amount: amount.to_le_bytes(),
713        }
714        .to_bytes(),
715    }
716}
717
718pub fn new_var(
719    signer: Pubkey,
720    provider: Pubkey,
721    id: u64,
722    commit: [u8; 32],
723    samples: u64,
724) -> Instruction {
725    let board_address = board_pda().0;
726    let config_address = config_pda().0;
727    let var_address = entropy_rng_api::state::var_pda(board_address, id).0;
728    Instruction {
729        program_id: crate::ID,
730        accounts: vec![
731            AccountMeta::new(signer, true),
732            AccountMeta::new(board_address, false),
733            AccountMeta::new(config_address, false),
734            AccountMeta::new(provider, false),
735            AccountMeta::new(var_address, false),
736            AccountMeta::new_readonly(system_program::ID, false),
737            AccountMeta::new_readonly(entropy_rng_api::ID, false),
738        ],
739        data: NewVar {
740            id: id.to_le_bytes(),
741            commit: commit,
742            samples: samples.to_le_bytes(),
743        }
744        .to_bytes(),
745    }
746}
747
748pub fn set_swap_program(signer: Pubkey, new_program: Pubkey) -> Instruction {
749    let config_address = config_pda().0;
750    Instruction {
751        program_id: crate::ID,
752        accounts: vec![
753            AccountMeta::new(signer, true),
754            AccountMeta::new(config_address, false),
755            AccountMeta::new_readonly(new_program, false),
756        ],
757        data: SetSwapProgram {}.to_bytes(),
758    }
759}
760
761pub fn set_var_address(signer: Pubkey, new_var_address: Pubkey) -> Instruction {
762    let board_address = board_pda().0;
763    let config_address = config_pda().0;
764    Instruction {
765        program_id: crate::ID,
766        accounts: vec![
767            AccountMeta::new(signer, true),
768            AccountMeta::new(board_address, false),
769            AccountMeta::new(config_address, false),
770            AccountMeta::new(new_var_address, false),
771        ],
772        data: SetVarAddress {}.to_bytes(),
773    }
774}
775
776/// Migrate: Extend Treasury struct with liquidity field.
777/// This migration ensures the Treasury account has the new liquidity field available.
778/// Must be called by the admin.
779/// Accounts: signer, config, treasury, system_program
780pub fn migrate(signer: Pubkey) -> Instruction {
781    let config_address = config_pda().0;
782    let treasury_address = treasury_pda().0;
783    Instruction {
784        program_id: crate::ID,
785        accounts: vec![
786            AccountMeta::new(signer, true),
787            AccountMeta::new(config_address, false),
788            AccountMeta::new(treasury_address, false),
789            AccountMeta::new_readonly(system_program::ID, false),
790        ],
791        data: Migrate {}.to_bytes(),
792    }
793}
794
795/// Create a referral account to become a referrer.
796pub fn create_referral(signer: Pubkey) -> Instruction {
797    let referral_address = referral_pda(signer).0;
798    Instruction {
799        program_id: crate::ID,
800        accounts: vec![
801            AccountMeta::new(signer, true),
802            AccountMeta::new(referral_address, false),
803            AccountMeta::new_readonly(system_program::ID, false),
804        ],
805        data: CreateReferral {}.to_bytes(),
806    }
807}
808
809/// Creates a Whitelist account for a shared access code.
810/// Admin-only instruction.
811/// Accounts: signer (admin), config, whitelist, system_program
812pub fn create_whitelist(
813    signer: Pubkey,
814    code_hash: [u8; 32],
815) -> Instruction {
816    let config_address = config_pda().0;
817    let (whitelist_address, _) = Whitelist::pda(code_hash);
818    Instruction {
819        program_id: crate::ID,
820        accounts: vec![
821            AccountMeta::new(signer, true), // signer (admin)
822            AccountMeta::new_readonly(config_address, false), // config
823            AccountMeta::new(whitelist_address, false), // whitelist
824            AccountMeta::new_readonly(system_program::ID, false), // system_program
825        ],
826        data: CreateWhitelist {
827            code_hash,
828        }
829        .to_bytes(),
830    }
831}
832
833/// Claim pending referral rewards (both SOL and OIL).
834/// 
835/// Account structure (for Fogo sessions):
836/// - Base: signer (payer), authority (user's wallet), referral, referral_tokens, mint, recipient, system_program, token_program, associated_token_program
837pub fn claim_referral(signer: Pubkey, authority: Pubkey) -> Instruction {
838    let referral_address = referral_pda(authority).0;
839    let referral_oil_address = get_associated_token_address(&referral_address, &MINT_ADDRESS);
840    let recipient_oil_address = get_associated_token_address(&authority, &MINT_ADDRESS);
841    Instruction {
842        program_id: crate::ID,
843        accounts: vec![
844            AccountMeta::new(signer, true), // 0: signer (payer)
845            AccountMeta::new(authority, false), // 1: authority (user's wallet, receives SOL)
846            AccountMeta::new(referral_address, false), // 2: referral
847            AccountMeta::new(referral_oil_address, false), // 3: referral_tokens (Referral account's OIL ATA)
848            AccountMeta::new(MINT_ADDRESS, false), // 4: mint
849            AccountMeta::new(recipient_oil_address, false), // 5: recipient (Recipient's OIL ATA - authority's wallet)
850            AccountMeta::new_readonly(system_program::ID, false), // 6: system_program
851            AccountMeta::new_readonly(spl_token::ID, false), // 7: token_program
852            AccountMeta::new_readonly(spl_associated_token_account::ID, false), // 8: associated_token_program
853        ],
854        data: ClaimReferral {}.to_bytes(),
855    }
856}
857
858/// Direct solo bid on an auction well (seize ownership).
859/// The bid amount is calculated on-chain as current_price + 1 lamport.
860/// User must have enough SOL in their wallet to cover the bid.
861/// 
862/// Account structure:
863/// - 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
864/// - If previous owner exists (optional): [previous_owner_miner, previous_owner]
865/// - If referrer is provided (optional): [referral]
866pub fn place_bid(
867    signer: Pubkey,
868    authority: Pubkey,
869    square_id: u64,
870    fee_collector: Pubkey,
871    previous_owner_miner: Option<Pubkey>, // Previous owner's miner PDA (if previous owner exists)
872    previous_owner: Option<Pubkey>, // Previous owner pubkey (if previous owner exists)
873    referrer: Option<Pubkey>, // Optional referrer pubkey for new miners
874) -> Instruction {
875    let well_address = well_pda(square_id).0;
876    let auction_address = auction_pda().0;
877    let treasury_address = treasury_pda().0;
878    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
879    let staking_pool_address = pool_pda().0;
880    let config_address = config_pda().0;
881    let mint_authority_address = oil_mint_api::state::authority_pda().0;
882    let bidder_miner_address = miner_pda(authority).0;
883    
884    let mut accounts = vec![
885        AccountMeta::new(signer, true), // 0: signer
886        AccountMeta::new(authority, false), // 1: authority
887    ];
888    
889    // Add program_signer and payer for Fogo sessions (these are added by the client, not here)
890    // For now, we'll add placeholders or the client will add them
891    
892    accounts.extend_from_slice(&[
893        AccountMeta::new(well_address, false), // well
894        AccountMeta::new(auction_address, false), // Must be writable for auction_program_log CPI
895        AccountMeta::new(treasury_address, false),
896        AccountMeta::new(treasury_tokens_address, false),
897        AccountMeta::new(MINT_ADDRESS, false),
898        AccountMeta::new(mint_authority_address, false),
899        AccountMeta::new_readonly(oil_mint_api::ID, false),
900        AccountMeta::new(staking_pool_address, false),
901        AccountMeta::new(fee_collector, false),
902        AccountMeta::new_readonly(config_address, false),
903        AccountMeta::new_readonly(spl_token::ID, false),
904        AccountMeta::new_readonly(system_program::ID, false),
905        AccountMeta::new_readonly(crate::ID, false), // oil_program
906        AccountMeta::new(bidder_miner_address, false), // bidder_miner
907    ]);
908    
909    // Add previous owner accounts if provided
910    if let (Some(miner_pubkey), Some(owner_pubkey)) = (previous_owner_miner, previous_owner) {
911        accounts.push(AccountMeta::new(miner_pubkey, false)); // previous_owner_miner
912        accounts.push(AccountMeta::new(owner_pubkey, false)); // previous_owner
913    }
914    
915    // Add referral account if referrer is provided
916    if let Some(referrer_pubkey) = referrer {
917        let referral_address = referral_pda(referrer_pubkey).0;
918        accounts.push(AccountMeta::new(referral_address, false)); // referral
919    }
920    
921    // Note: Wrapped token accounts are added by the client:
922    // - user_wrapped_sol (source)
923    // - treasury_wrapped_sol (temp ATA for all wrapped SOL - will be closed to get native SOL)
924    // - token_program, native_mint, ata_program
925    // The program distributes native SOL from treasury to pool and fee_collector after closing the temp ATA.
926    
927    Instruction {
928        program_id: crate::ID,
929        accounts,
930        data: instruction::PlaceBid {
931            square_id: square_id.to_le_bytes(),
932            referrer: referrer.unwrap_or(Pubkey::default()).to_bytes(),
933        }
934        .to_bytes(),
935    }
936}
937
938/// Claim auction-based OIL rewards
939/// - OIL rewards: from current ownership and previous ownership (pre-minted)
940/// 
941/// Account structure:
942/// - 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
943/// - 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)
944/// Claim auction-based OIL rewards
945/// 
946/// Account structure:
947/// - 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
948/// - If miner has referrer (required): [miner_referrer, referral_referrer, referral_referrer_oil_ata]
949pub fn claim_auction_oil(
950    signer: Pubkey,
951    well_mask: u8, // Bitmask: bit 0 = well 0, bit 1 = well 1, etc.
952    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
953    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
954    referrer_referral_oil_ata: Option<Pubkey>, // Referrer's referral OIL ATA (if miner has referrer)
955) -> Instruction {
956    let miner_address = miner_pda(signer).0;
957    let well_0_address = well_pda(0).0;
958    let well_1_address = well_pda(1).0;
959    let well_2_address = well_pda(2).0;
960    let well_3_address = well_pda(3).0;
961    let auction_address = auction_pda().0;
962    let treasury_address = treasury_pda().0;
963    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
964    let recipient_address = get_associated_token_address(&signer, &MINT_ADDRESS);
965    let mint_authority_address = oil_mint_api::state::authority_pda().0;
966    
967    let mut accounts = vec![
968        AccountMeta::new(signer, true),
969        AccountMeta::new(miner_address, false),
970        AccountMeta::new(well_0_address, false),
971        AccountMeta::new(well_1_address, false),
972        AccountMeta::new(well_2_address, false),
973        AccountMeta::new(well_3_address, false),
974        AccountMeta::new(auction_address, false),
975        AccountMeta::new(treasury_address, false),
976        AccountMeta::new(treasury_tokens_address, false),
977        AccountMeta::new(MINT_ADDRESS, false),
978        AccountMeta::new(mint_authority_address, false),
979        AccountMeta::new_readonly(oil_mint_api::ID, false),
980        AccountMeta::new(recipient_address, false),
981        AccountMeta::new_readonly(spl_token::ID, false),
982        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
983        AccountMeta::new_readonly(system_program::ID, false),
984        AccountMeta::new_readonly(crate::ID, false),
985    ];
986    
987    // Add referrer accounts if provided (required if miner has referrer)
988    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
989        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
990        accounts.push(AccountMeta::new(miner_pubkey, false));
991        accounts.push(AccountMeta::new(referral_pubkey, false));
992        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
993    }
994    
995    Instruction {
996        program_id: crate::ID,
997        accounts,
998        data: ClaimAuctionOIL {
999            well_mask,
1000        }
1001        .to_bytes(),
1002    }
1003}
1004
1005/// Claim auction-based SOL rewards
1006/// 
1007/// Account structure:
1008/// - Base: signer (writable), miner, treasury, auction, system_program, oil_program
1009/// - If miner has referrer (required): [miner_referrer, referral_referrer]
1010pub fn claim_auction_sol(
1011    signer: Pubkey,
1012    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
1013    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
1014) -> Instruction {
1015    let miner_address = miner_pda(signer).0;
1016    let (auction_address, _) = auction_pda();
1017    let treasury_address = treasury_pda().0;
1018    
1019    let mut accounts = vec![
1020        AccountMeta::new(signer, true), // signer and writable for receiving SOL
1021        AccountMeta::new(miner_address, false),
1022        AccountMeta::new(treasury_address, false),
1023        AccountMeta::new(auction_address, false),
1024        AccountMeta::new_readonly(system_program::ID, false),
1025        AccountMeta::new_readonly(crate::ID, false),
1026    ];
1027    
1028    // Add referrer accounts if provided (required if miner has referrer)
1029    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
1030        accounts.push(AccountMeta::new(miner_pubkey, false));
1031        accounts.push(AccountMeta::new(referral_pubkey, false));
1032    }
1033    
1034    Instruction {
1035        program_id: crate::ID,
1036        accounts,
1037        data: ClaimAuctionSOL {
1038            _reserved: 0,
1039        }
1040        .to_bytes(),
1041    }
1042}
1043
1044// ============================================================================
1045// FOGO Session SDK Functions
1046// ============================================================================
1047
1048pub fn deploy_with_session(
1049    signer: Pubkey,
1050    authority: Pubkey,
1051    program_signer: Pubkey,
1052    payer: Pubkey,
1053    amount: u64,
1054    round_id: u64,
1055    squares: [bool; 25],
1056    referrer: Option<Pubkey>,
1057    pooled: bool,
1058) -> Instruction {
1059    let automation_address = automation_pda(authority).0;
1060    let board_address = board_pda().0;
1061    let miner_address = miner_pda(authority).0;
1062    let round_address = round_pda(round_id).0;
1063    let entropy_var_address = entropy_rng_api::state::var_pda(board_address, 0).0;
1064
1065    let mut mask: u32 = 0;
1066    for (i, &square) in squares.iter().enumerate() {
1067        if square {
1068            mask |= 1 << i;
1069        }
1070    }
1071    
1072    let referrer_pubkey = referrer.unwrap_or(Pubkey::default());
1073    let user_wrapped_sol_ata = get_associated_token_address(&authority, &SOL_MINT);
1074    let round_wrapped_sol_ata = get_associated_token_address(&round_address, &SOL_MINT);
1075
1076    let mut accounts = vec![
1077        AccountMeta::new(signer, true),
1078        AccountMeta::new(authority, false),
1079        AccountMeta::new_readonly(program_signer, false),
1080        AccountMeta::new(payer, false),
1081        AccountMeta::new(automation_address, false),
1082        AccountMeta::new(board_address, false),
1083        AccountMeta::new(miner_address, false),
1084        AccountMeta::new(round_address, false),
1085        AccountMeta::new_readonly(system_program::ID, false),
1086        AccountMeta::new_readonly(crate::ID, false),
1087        AccountMeta::new(user_wrapped_sol_ata, false),
1088        AccountMeta::new(round_wrapped_sol_ata, false),
1089        AccountMeta::new_readonly(spl_token::ID, false),
1090        AccountMeta::new_readonly(SOL_MINT, false),
1091        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1092    ];
1093    
1094    if referrer_pubkey != Pubkey::default() {
1095        let referral_address = referral_pda(referrer_pubkey).0;
1096        accounts.push(AccountMeta::new(referral_address, false));
1097    }
1098    
1099    accounts.push(AccountMeta::new(entropy_var_address, false));
1100    accounts.push(AccountMeta::new_readonly(entropy_rng_api::ID, false));
1101
1102    Instruction {
1103        program_id: crate::ID,
1104        accounts,
1105        data: Deploy {
1106            amount: amount.to_le_bytes(),
1107            squares: mask.to_le_bytes(),
1108            referrer: referrer_pubkey.to_bytes(),
1109            pooled: if pooled { 1 } else { 0 },
1110        }
1111        .to_bytes(),
1112    }
1113}
1114
1115pub fn automate_with_session(
1116    signer: Pubkey,
1117    authority: Pubkey,
1118    program_signer: Pubkey,
1119    payer: Pubkey,
1120    amount: u64,
1121    deposit: u64,
1122    executor: Pubkey,
1123    fee: u64,
1124    mask: u64,
1125    strategy: u8,
1126    reload: bool,
1127    referrer: Option<Pubkey>,
1128    pooled: bool,
1129    is_new_miner: bool,
1130) -> Instruction {
1131    let automation_address = automation_pda(authority).0;
1132    let miner_address = miner_pda(authority).0;
1133    let referrer_pk = referrer.unwrap_or(Pubkey::default());
1134    let user_wrapped_sol_ata = get_associated_token_address(&authority, &SOL_MINT);
1135    let automation_wrapped_sol_ata = get_associated_token_address(&automation_address, &SOL_MINT);
1136    
1137    let mut accounts = vec![
1138        AccountMeta::new(signer, true),
1139        AccountMeta::new(authority, false),
1140        AccountMeta::new_readonly(program_signer, false),
1141        AccountMeta::new(payer, false),
1142        AccountMeta::new(automation_address, false),
1143        AccountMeta::new(executor, false),
1144        AccountMeta::new(miner_address, false),
1145        AccountMeta::new_readonly(system_program::ID, false),
1146        AccountMeta::new_readonly(crate::ID, false),
1147        AccountMeta::new(user_wrapped_sol_ata, false),
1148        AccountMeta::new(automation_wrapped_sol_ata, false),
1149        AccountMeta::new_readonly(spl_token::ID, false),
1150        AccountMeta::new_readonly(SOL_MINT, false),
1151        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1152    ];
1153    
1154    if is_new_miner && referrer.is_some() && referrer_pk != Pubkey::default() {
1155        let referral_address = referral_pda(referrer_pk).0;
1156        accounts.push(AccountMeta::new(referral_address, false));
1157    }
1158    
1159    Instruction {
1160        program_id: crate::ID,
1161        accounts,
1162        data: Automate {
1163            amount: amount.to_le_bytes(),
1164            deposit: deposit.to_le_bytes(),
1165            fee: fee.to_le_bytes(),
1166            mask: mask.to_le_bytes(),
1167            strategy: strategy as u8,
1168            reload: (reload as u64).to_le_bytes(),
1169            referrer: referrer_pk.to_bytes(),
1170            pooled: pooled as u8,
1171        }
1172        .to_bytes(),
1173    }
1174}
1175
1176pub fn place_bid_with_session(
1177    signer: Pubkey,
1178    authority: Pubkey,
1179    program_signer: Pubkey,
1180    payer: Pubkey,
1181    square_id: u64,
1182    fee_collector: Pubkey,
1183    previous_owner_miner: Option<Pubkey>,
1184    previous_owner: Option<Pubkey>,
1185    referrer: Option<Pubkey>,
1186) -> Instruction {
1187    let well_address = well_pda(square_id).0;
1188    let auction_address = auction_pda().0;
1189    let treasury_address = treasury_pda().0;
1190    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
1191    let staking_pool_address = pool_pda().0;
1192    let config_address = config_pda().0;
1193    let mint_authority_address = oil_mint_api::state::authority_pda().0;
1194    let bidder_miner_address = miner_pda(authority).0;
1195    let user_wrapped_sol_ata = get_associated_token_address(&authority, &SOL_MINT);
1196    let treasury_wrapped_sol_ata = get_associated_token_address(&treasury_address, &SOL_MINT);
1197    
1198    let mut accounts = vec![
1199        AccountMeta::new(signer, true),
1200        AccountMeta::new(authority, false),
1201        AccountMeta::new_readonly(program_signer, false),
1202        AccountMeta::new(payer, false),
1203        AccountMeta::new(well_address, false),
1204        AccountMeta::new(auction_address, false),
1205        AccountMeta::new(treasury_address, false),
1206        AccountMeta::new(treasury_tokens_address, false),
1207        AccountMeta::new(MINT_ADDRESS, false),
1208        AccountMeta::new(mint_authority_address, false),
1209        AccountMeta::new_readonly(oil_mint_api::ID, false),
1210        AccountMeta::new(staking_pool_address, false),
1211        AccountMeta::new(fee_collector, false),
1212        AccountMeta::new_readonly(config_address, false),
1213        AccountMeta::new_readonly(spl_token::ID, false),
1214        AccountMeta::new_readonly(system_program::ID, false),
1215        AccountMeta::new_readonly(crate::ID, false),
1216        AccountMeta::new(bidder_miner_address, false),
1217    ];
1218    
1219    if let (Some(miner_pubkey), Some(owner_pubkey)) = (previous_owner_miner, previous_owner) {
1220        accounts.push(AccountMeta::new(miner_pubkey, false));
1221        accounts.push(AccountMeta::new(owner_pubkey, false));
1222    }
1223    
1224    if let Some(referrer_pubkey) = referrer {
1225        let referral_address = referral_pda(referrer_pubkey).0;
1226        accounts.push(AccountMeta::new(referral_address, false));
1227    }
1228    
1229    accounts.extend_from_slice(&[
1230        AccountMeta::new(user_wrapped_sol_ata, false),
1231        AccountMeta::new(treasury_wrapped_sol_ata, false),
1232        AccountMeta::new_readonly(spl_token::ID, false),
1233        AccountMeta::new_readonly(SOL_MINT, false),
1234        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1235    ]);
1236    
1237    Instruction {
1238        program_id: crate::ID,
1239        accounts,
1240        data: instruction::PlaceBid {
1241            square_id: square_id.to_le_bytes(),
1242            referrer: referrer.unwrap_or(Pubkey::default()).to_bytes(),
1243        }
1244        .to_bytes(),
1245    }
1246}
1247
1248pub fn claim_auction_oil_with_session(
1249    signer: Pubkey,
1250    authority: Pubkey,
1251    program_signer: Pubkey,
1252    payer: Pubkey,
1253    well_mask: u8,
1254    referrer_miner: Option<Pubkey>,
1255    referrer_referral: Option<Pubkey>,
1256    referrer_referral_oil_ata: Option<Pubkey>,
1257) -> Instruction {
1258    let miner_address = miner_pda(authority).0;
1259    let well_0_address = well_pda(0).0;
1260    let well_1_address = well_pda(1).0;
1261    let well_2_address = well_pda(2).0;
1262    let well_3_address = well_pda(3).0;
1263    let auction_address = auction_pda().0;
1264    let treasury_address = treasury_pda().0;
1265    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
1266    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1267    let mint_authority_address = oil_mint_api::state::authority_pda().0;
1268    
1269    let mut accounts = vec![
1270        AccountMeta::new(signer, true),
1271        AccountMeta::new(authority, false),
1272        AccountMeta::new_readonly(program_signer, false),
1273        AccountMeta::new(payer, false),
1274        AccountMeta::new(miner_address, false),
1275        AccountMeta::new(well_0_address, false),
1276        AccountMeta::new(well_1_address, false),
1277        AccountMeta::new(well_2_address, false),
1278        AccountMeta::new(well_3_address, false),
1279        AccountMeta::new(auction_address, false),
1280        AccountMeta::new(treasury_address, false),
1281        AccountMeta::new(treasury_tokens_address, false),
1282        AccountMeta::new(MINT_ADDRESS, false),
1283        AccountMeta::new(mint_authority_address, false),
1284        AccountMeta::new_readonly(oil_mint_api::ID, false),
1285        AccountMeta::new(recipient_address, false),
1286        AccountMeta::new_readonly(spl_token::ID, false),
1287        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1288        AccountMeta::new_readonly(system_program::ID, false),
1289        AccountMeta::new_readonly(crate::ID, false),
1290    ];
1291    
1292    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
1293        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
1294        accounts.push(AccountMeta::new(miner_pubkey, false));
1295        accounts.push(AccountMeta::new(referral_pubkey, false));
1296        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
1297    }
1298    
1299    Instruction {
1300        program_id: crate::ID,
1301        accounts,
1302        data: ClaimAuctionOIL {
1303            well_mask,
1304        }
1305        .to_bytes(),
1306    }
1307}
1308
1309pub fn claim_auction_sol_with_session(
1310    signer: Pubkey,
1311    authority: Pubkey,
1312    program_signer: Pubkey,
1313    payer: Pubkey,
1314    referrer_miner: Option<Pubkey>,
1315    referrer_referral: Option<Pubkey>,
1316) -> Instruction {
1317    let miner_address = miner_pda(authority).0;
1318    let (auction_address, _) = auction_pda();
1319    let treasury_address = treasury_pda().0;
1320    
1321    let mut accounts = vec![
1322        AccountMeta::new(signer, true),
1323        AccountMeta::new(authority, false),
1324        AccountMeta::new_readonly(program_signer, false),
1325        AccountMeta::new(payer, false),
1326        AccountMeta::new(miner_address, false),
1327        AccountMeta::new(treasury_address, false),
1328        AccountMeta::new(auction_address, false),
1329        AccountMeta::new_readonly(system_program::ID, false),
1330        AccountMeta::new_readonly(crate::ID, false),
1331    ];
1332    
1333    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
1334        accounts.push(AccountMeta::new(miner_pubkey, false));
1335        accounts.push(AccountMeta::new(referral_pubkey, false));
1336    }
1337    
1338    Instruction {
1339        program_id: crate::ID,
1340        accounts,
1341        data: ClaimAuctionSOL {
1342            _reserved: 0,
1343        }
1344        .to_bytes(),
1345    }
1346}
1347
1348pub fn claim_sol_with_session(
1349    signer: Pubkey,
1350    authority: Pubkey,
1351    program_signer: Pubkey,
1352    payer: Pubkey,
1353    referrer_miner: Option<Pubkey>,
1354    referrer_referral: Option<Pubkey>,
1355) -> Instruction {
1356    let miner_address = miner_pda(authority).0;
1357    
1358    let mut accounts = vec![
1359        AccountMeta::new(signer, true),
1360        AccountMeta::new(authority, false),
1361        AccountMeta::new_readonly(program_signer, false),
1362        AccountMeta::new(payer, false),
1363        AccountMeta::new(miner_address, false),
1364        AccountMeta::new_readonly(system_program::ID, false),
1365    ];
1366    
1367    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
1368        accounts.push(AccountMeta::new(miner_pubkey, false));
1369        accounts.push(AccountMeta::new(referral_pubkey, false));
1370    }
1371    
1372    Instruction {
1373        program_id: crate::ID,
1374        accounts,
1375        data: ClaimSOL {}.to_bytes(),
1376    }
1377}
1378
1379pub fn claim_oil_with_session(
1380    signer: Pubkey,
1381    authority: Pubkey,
1382    program_signer: Pubkey,
1383    payer: Pubkey,
1384    referrer_miner: Option<Pubkey>,
1385    referrer_referral: Option<Pubkey>,
1386    referrer_referral_oil_ata: Option<Pubkey>,
1387) -> Instruction {
1388    let miner_address = miner_pda(authority).0;
1389    let treasury_address = treasury_pda().0;
1390    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
1391    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1392    
1393    let mut accounts = vec![
1394        AccountMeta::new(signer, true),
1395        AccountMeta::new(authority, false),
1396        AccountMeta::new_readonly(program_signer, false),
1397        AccountMeta::new(payer, false),
1398        AccountMeta::new(miner_address, false),
1399        AccountMeta::new(MINT_ADDRESS, false),
1400        AccountMeta::new(recipient_address, false),
1401        AccountMeta::new(treasury_address, false),
1402        AccountMeta::new(treasury_tokens_address, false),
1403        AccountMeta::new_readonly(system_program::ID, false),
1404        AccountMeta::new_readonly(spl_token::ID, false),
1405        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1406    ];
1407    
1408    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
1409        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
1410        accounts.push(AccountMeta::new(miner_pubkey, false));
1411        accounts.push(AccountMeta::new(referral_pubkey, false));
1412        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
1413    }
1414    
1415    Instruction {
1416        program_id: crate::ID,
1417        accounts,
1418        data: ClaimOIL {}.to_bytes(),
1419    }
1420}
1421
1422pub fn withdraw_with_session(
1423    signer: Pubkey,
1424    authority: Pubkey,
1425    program_signer: Pubkey,
1426    payer: Pubkey,
1427    amount: u64,
1428    stake_id: u64,
1429) -> Instruction {
1430    let stake_address = stake_pda_with_id(authority, stake_id).0;
1431    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
1432    let mint_address = MINT_ADDRESS;
1433    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS);
1434    let pool_address = pool_pda().0;
1435    let pool_tokens_address = pool_tokens_address();
1436    let miner_address = miner_pda(authority).0;
1437    let treasury_address = treasury_pda().0;
1438    let treasury_tokens_address = treasury_tokens_address();
1439    
1440    Instruction {
1441        program_id: crate::ID,
1442        accounts: vec![
1443            AccountMeta::new(signer, true),
1444            AccountMeta::new(authority, false),
1445            AccountMeta::new_readonly(program_signer, false),
1446            AccountMeta::new(payer, false),
1447            AccountMeta::new(mint_address, false),
1448            AccountMeta::new(recipient_address, false),
1449            AccountMeta::new(stake_address, false),
1450            AccountMeta::new(stake_tokens_address, false),
1451            AccountMeta::new(pool_address, false),
1452            AccountMeta::new(pool_tokens_address, false),
1453            AccountMeta::new(miner_address, false),
1454            AccountMeta::new(treasury_address, false),
1455            AccountMeta::new(treasury_tokens_address, false),
1456            AccountMeta::new_readonly(system_program::ID, false),
1457            AccountMeta::new_readonly(spl_token::ID, false),
1458            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1459        ],
1460        data: Withdraw {
1461            amount: amount.to_le_bytes(),
1462            stake_id: stake_id.to_le_bytes(),
1463        }
1464        .to_bytes(),
1465    }
1466}