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
36// pub fn initialize(
37//     signer: Pubkey,
38//     barrel_authority: Pubkey,
39//     fee_collector: Pubkey,
40//     swap_program: Pubkey,
41//     var_address: Pubkey,
42//     admin_fee: u64,
43// ) -> Instruction {
44//     let board_address = board_pda().0;
45//     let config_address = config_pda().0;
46//     let mint_address = MINT_ADDRESS;
47//     let treasury_address = TREASURY_ADDRESS;
48//     let treasury_tokens_address = treasury_tokens_address();
49//     Instruction {
50//         program_id: crate::ID,
51//         accounts: vec![
52//             AccountMeta::new(signer, true),
53//             AccountMeta::new(board_address, false),
54//             AccountMeta::new(config_address, false),
55//             AccountMeta::new(mint_address, false),
56//             AccountMeta::new(treasury_address, false),
57//             AccountMeta::new(treasury_tokens_address, false),
58//             AccountMeta::new_readonly(system_program::ID, false),
59//             AccountMeta::new_readonly(spl_token::ID, false),
60//             AccountMeta::new_readonly(spl_associated_token_account::ID, false),
61//         ],
62//         data: Initialize {
63//             barrel_authority: barrel_authority.to_bytes(),
64//             fee_collector: fee_collector.to_bytes(),
65//             swap_program: swap_program.to_bytes(),
66//             var_address: var_address.to_bytes(),
67//             admin_fee: admin_fee.to_le_bytes(),
68//         }
69//         .to_bytes(),
70//     }
71// }
72
73// let [signer_info, automation_info, executor_info, miner_info, system_program] = accounts else {
74
75/// Set up automation for a miner. If the miner doesn't exist yet, pass a referrer to set it.
76/// If a referrer is provided and the miner is new, the referral account must be included.
77pub fn automate(
78    signer: 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(signer).0;
91    let miner_address = miner_pda(signer).0;
92    let referrer_pk = referrer.unwrap_or(Pubkey::default());
93    
94    let mut accounts = vec![
95            AccountMeta::new(signer, true),
96            AccountMeta::new(automation_address, false),
97            AccountMeta::new(executor, false),
98            AccountMeta::new(miner_address, false),
99            AccountMeta::new_readonly(system_program::ID, false),
100    ];
101    
102    // Add referral account if referrer is provided and miner is new (for incrementing total_referred)
103    if is_new_miner && referrer.is_some() && referrer_pk != Pubkey::default() {
104        let referral_address = referral_pda(referrer_pk).0;
105        accounts.push(AccountMeta::new(referral_address, false));
106    }
107    
108    Instruction {
109        program_id: crate::ID,
110        accounts,
111        data: Automate {
112            amount: amount.to_le_bytes(),
113            deposit: deposit.to_le_bytes(),
114            fee: fee.to_le_bytes(),
115            mask: mask.to_le_bytes(),
116            strategy: strategy as u8,
117            reload: (reload as u64).to_le_bytes(),
118            referrer: referrer_pk.to_bytes(),
119            pooled: pooled as u8,
120        }
121        .to_bytes(),
122    }
123}
124
125/// Claim SOL rewards with single-tier referral system.
126/// 
127/// If the miner has a referrer, 1.0% of the claim goes to the referrer.
128/// 
129/// Account structure:
130/// - Base: signer, miner, system_program
131/// - If miner has referrer (required): [miner_referrer, referral_referrer]
132pub fn claim_sol(
133    signer: Pubkey,
134    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
135    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
136) -> Instruction {
137    let miner_address = miner_pda(signer).0;
138    
139    let mut accounts = vec![
140        AccountMeta::new(signer, true),
141        AccountMeta::new(miner_address, false),
142        AccountMeta::new_readonly(system_program::ID, false),
143    ];
144    
145    // Add referrer accounts if provided (required if miner has referrer)
146    if let (Some(miner_pubkey), Some(referral_pubkey)) = (referrer_miner, referrer_referral) {
147        accounts.push(AccountMeta::new(miner_pubkey, false));
148        accounts.push(AccountMeta::new(referral_pubkey, false));
149    }
150    
151    Instruction {
152        program_id: crate::ID,
153        accounts,
154        data: ClaimSOL {}.to_bytes(),
155    }
156}
157
158// let [signer_info, miner_info, mint_info, recipient_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] =
159
160/// Claim OIL rewards with single-tier referral system.
161/// 
162/// If the miner has a referrer, 1.0% of the claim goes to the referrer.
163/// 
164/// Account structure:
165/// - Base: signer, miner, mint, recipient, treasury, treasury_tokens, system_program, token_program, associated_token_program
166/// - If miner has referrer (required): [miner_referrer, referral_referrer, referral_referrer_oil_ata]
167pub fn claim_oil(
168    signer: Pubkey,
169    referrer_miner: Option<Pubkey>, // Referrer's miner PDA (if miner has referrer)
170    referrer_referral: Option<Pubkey>, // Referrer's referral PDA (if miner has referrer)
171    referrer_referral_oil_ata: Option<Pubkey>, // Referrer's referral OIL ATA (if miner has referrer)
172) -> Instruction {
173    let miner_address = miner_pda(signer).0;
174    let treasury_address = treasury_pda().0;
175    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
176    let recipient_address = get_associated_token_address(&signer, &MINT_ADDRESS);
177    
178    let mut accounts = vec![
179        AccountMeta::new(signer, true),
180        AccountMeta::new(miner_address, false),
181        AccountMeta::new(MINT_ADDRESS, false),
182        AccountMeta::new(recipient_address, false),
183        AccountMeta::new(treasury_address, false),
184        AccountMeta::new(treasury_tokens_address, false),
185        AccountMeta::new_readonly(system_program::ID, false),
186        AccountMeta::new_readonly(spl_token::ID, false),
187        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
188    ];
189    
190    // Add referrer accounts if provided (required if miner has referrer)
191    if let (Some(miner_pubkey), Some(referral_pubkey), Some(oil_ata_pubkey)) = 
192        (referrer_miner, referrer_referral, referrer_referral_oil_ata) {
193        accounts.push(AccountMeta::new(miner_pubkey, false));
194        accounts.push(AccountMeta::new(referral_pubkey, false));
195        accounts.push(AccountMeta::new(oil_ata_pubkey, false));
196    }
197    
198    Instruction {
199        program_id: crate::ID,
200        accounts,
201        data: ClaimOIL {}.to_bytes(),
202    }
203}
204
205
206pub fn close(signer: Pubkey, round_id: u64, rent_payer: Pubkey) -> Instruction {
207    let board_address = board_pda().0;
208    let round_address = round_pda(round_id).0;
209    let treasury_address = TREASURY_ADDRESS;
210    Instruction {
211        program_id: crate::ID,
212        accounts: vec![
213            AccountMeta::new(signer, true),
214            AccountMeta::new(board_address, false),
215            AccountMeta::new(rent_payer, false),
216            AccountMeta::new(round_address, false),
217            AccountMeta::new(treasury_address, false),
218            AccountMeta::new_readonly(system_program::ID, false),
219        ],
220        data: Close {}.to_bytes(),
221    }
222}
223
224/// Deploy SOL to prospect on squares. Pass a referrer pubkey for new miners to set up referral.
225/// Set `pooled` to true to join the mining pool (rewards shared proportionally).
226pub fn deploy(
227    signer: Pubkey,
228    authority: Pubkey,
229    amount: u64,
230    round_id: u64,
231    squares: [bool; 25],
232    referrer: Option<Pubkey>,
233    pooled: bool,
234    access_code_hash: Option<[u8; 32]>,
235) -> Instruction {
236    let automation_address = automation_pda(authority).0;
237    let board_address = board_pda().0;
238    let config_address = config_pda().0;
239    let miner_address = miner_pda(authority).0;
240    let round_address = round_pda(round_id).0;
241    let entropy_var_address = entropy_rng_api::state::var_pda(board_address, 0).0;
242
243    // Convert array of 25 booleans into a 32-bit mask where each bit represents whether
244    // that square index is selected (1) or not (0)
245    let mut mask: u32 = 0;
246    for (i, &square) in squares.iter().enumerate() {
247        if square {
248            mask |= 1 << i;
249        }
250    }
251    
252    // Get referrer bytes (default to zero pubkey if no referrer).
253    let referrer_pubkey = referrer.unwrap_or(Pubkey::default());
254    let referrer_bytes = referrer_pubkey.to_bytes();
255
256    // Derive wrapped SOL ATAs
257    let user_wrapped_sol_ata = get_associated_token_address(&authority, &SOL_MINT);
258    let round_wrapped_sol_ata = get_associated_token_address(&round_address, &SOL_MINT);
259
260    // Build accounts list - must match program structure:
261    // Oil accounts: base (9) + token (5) + optional referral (1) = 14-15
262    // Entropy accounts: var + program = 2 (always exactly 2)
263    let mut accounts = vec![
264        // Base accounts (9)
265        AccountMeta::new(signer, true), // 0: signer
266        AccountMeta::new(authority, false), // 1: authority
267        AccountMeta::new(automation_address, false), // 2: automation
268        AccountMeta::new(board_address, false), // 3: board
269        AccountMeta::new_readonly(config_address, false), // 4: config
270        AccountMeta::new(miner_address, false), // 5: miner
271        AccountMeta::new(round_address, false), // 6: round
272        AccountMeta::new_readonly(system_program::ID, false), // 7: system_program
273        AccountMeta::new_readonly(crate::ID, false), // 8: oil_program
274        // Token accounts (5)
275        AccountMeta::new(user_wrapped_sol_ata, false), // 9: user_wrapped_sol
276        AccountMeta::new(round_wrapped_sol_ata, false), // 10: round_wrapped_sol
277        AccountMeta::new_readonly(spl_token::ID, false), // 11: token_program
278        AccountMeta::new_readonly(SOL_MINT, false), // 12: mint (SOL_MINT)
279        AccountMeta::new_readonly(spl_associated_token_account::ID, false), // 13: associated_token_program
280    ];
281    
282    // Add referral account if referrer is provided (in oil_accounts, before code account)
283    if referrer_pubkey != Pubkey::default() {
284        let referral_address = referral_pda(referrer_pubkey).0;
285        accounts.push(AccountMeta::new(referral_address, false)); // referral (optional, in oil_accounts)
286    }
287    
288    // Add Code account if access_code_hash is provided (in oil_accounts, after referral if present)
289    let access_code_hash_bytes = access_code_hash.unwrap_or([0; 32]);
290    if access_code_hash_bytes != [0; 32] {
291        let (code_address, _) = Code::pda(access_code_hash_bytes, authority);
292        accounts.push(AccountMeta::new(code_address, false)); // code (optional, in oil_accounts)
293    }
294    
295    // Entropy accounts (always exactly 2, come after all oil_accounts)
296    accounts.push(AccountMeta::new(entropy_var_address, false)); // entropy_var
297    accounts.push(AccountMeta::new_readonly(entropy_rng_api::ID, false)); // entropy_program
298
299    Instruction {
300        program_id: crate::ID,
301        accounts,
302        data: Deploy {
303            amount: amount.to_le_bytes(),
304            squares: mask.to_le_bytes(),
305            referrer: referrer_bytes,
306            pooled: if pooled { 1 } else { 0 },
307            access_code_hash: access_code_hash_bytes,
308        }
309        .to_bytes(),
310    }
311}
312
313/// Deploy instruction for automation (omits wrapped token accounts since automation uses native SOL)
314/// Account structure: base (9) + token programs only (3) + optional referral (1) + optional code (1) + entropy (2) = 12-16 accounts
315pub fn deploy_auto(
316    signer: Pubkey,
317    authority: Pubkey,
318    amount: u64,
319    round_id: u64,
320    squares: [bool; 25],
321    referrer: Option<Pubkey>,
322    pooled: bool,
323    access_code_hash: Option<[u8; 32]>,
324) -> Instruction {
325    let automation_address = automation_pda(authority).0;
326    let board_address = board_pda().0;
327    let config_address = config_pda().0;
328    let miner_address = miner_pda(authority).0;
329    let round_address = round_pda(round_id).0;
330    let entropy_var_address = entropy_rng_api::state::var_pda(board_address, 0).0;
331
332    // Convert array of 25 booleans into a 32-bit mask where each bit represents whether
333    // that square index is selected (1) or not (0)
334    let mut mask: u32 = 0;
335    for (i, &square) in squares.iter().enumerate() {
336        if square {
337            mask |= 1 << i;
338        }
339    }
340    
341    // Get referrer bytes (default to zero pubkey if no referrer).
342    let referrer_pubkey = referrer.unwrap_or(Pubkey::default());
343    let referrer_bytes = referrer_pubkey.to_bytes();
344
345    // Build accounts list - for automation, omit wrapped token ATAs:
346    // Base (9) + token programs only (3) + optional referral (1) = 12-13
347    // Entropy accounts: var + program = 2 (always exactly 2)
348    // Note: Program allows 12 accounts even when signer != authority (automation pattern)
349    let mut accounts = vec![
350        // Base accounts (9)
351        AccountMeta::new(signer, true), // 0: signer
352        AccountMeta::new(authority, false), // 1: authority
353        AccountMeta::new(automation_address, false), // 2: automation
354        AccountMeta::new(board_address, false), // 3: board
355        AccountMeta::new_readonly(config_address, false), // 4: config
356        AccountMeta::new(miner_address, false), // 5: miner
357        AccountMeta::new(round_address, false), // 6: round
358        AccountMeta::new_readonly(system_program::ID, false), // 7: system_program
359        AccountMeta::new_readonly(crate::ID, false), // 8: oil_program
360        // Token programs only (3) - no ATAs for automation
361        AccountMeta::new_readonly(spl_token::ID, false), // 9: token_program
362        AccountMeta::new_readonly(SOL_MINT, false), // 10: mint (SOL_MINT)
363        AccountMeta::new_readonly(spl_associated_token_account::ID, false), // 11: associated_token_program
364    ];
365    
366    // Add referral account if referrer is provided (in oil_accounts, before code account)
367    if referrer_pubkey != Pubkey::default() {
368        let referral_address = referral_pda(referrer_pubkey).0;
369        accounts.push(AccountMeta::new(referral_address, false)); // referral (optional, in oil_accounts)
370    }
371    
372    // Add Code account if access_code_hash is provided (in oil_accounts, after referral if present)
373    let access_code_hash_bytes = access_code_hash.unwrap_or([0; 32]);
374    if access_code_hash_bytes != [0; 32] {
375        let (code_address, _) = Code::pda(access_code_hash_bytes, authority);
376        accounts.push(AccountMeta::new(code_address, false)); // code (optional, in oil_accounts)
377    }
378    
379    // Entropy accounts (always exactly 2, come after all oil_accounts)
380    accounts.push(AccountMeta::new(entropy_var_address, false)); // entropy_var
381    accounts.push(AccountMeta::new_readonly(entropy_rng_api::ID, false)); // entropy_program
382
383    Instruction {
384        program_id: crate::ID,
385        accounts,
386        data: Deploy {
387            amount: amount.to_le_bytes(),
388            squares: mask.to_le_bytes(),
389            referrer: referrer_bytes,
390            pooled: if pooled { 1 } else { 0 },
391            access_code_hash: access_code_hash_bytes,
392        }
393        .to_bytes(),
394    }
395}
396
397// 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] =
398
399pub fn buyback(signer: Pubkey, swap_accounts: &[AccountMeta], swap_data: &[u8]) -> Instruction {
400    let board_address = board_pda().0;
401    let config_address = config_pda().0;
402    let mint_address = MINT_ADDRESS;
403    let treasury_address = TREASURY_ADDRESS;
404    let treasury_oil_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
405    let treasury_sol_address = get_associated_token_address(&treasury_address, &SOL_MINT);
406    let mut accounts = vec![
407        AccountMeta::new(signer, true),
408        AccountMeta::new(board_address, false),
409        AccountMeta::new_readonly(config_address, false),
410        AccountMeta::new(mint_address, false),
411        AccountMeta::new(treasury_address, false),
412        AccountMeta::new(treasury_oil_address, false),
413        AccountMeta::new(treasury_sol_address, false),
414        AccountMeta::new_readonly(spl_token::ID, false),
415        AccountMeta::new_readonly(crate::ID, false),
416    ];
417    for account in swap_accounts.iter() {
418        let mut acc_clone = account.clone();
419        acc_clone.is_signer = false;
420        accounts.push(acc_clone);
421    }
422    let mut data = Buyback {}.to_bytes();
423    data.extend_from_slice(swap_data);
424    Instruction {
425        program_id: crate::ID,
426        accounts,
427        data,
428    }
429}
430
431// 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] =
432
433pub fn reset(
434    signer: Pubkey,
435    fee_collector: Pubkey,
436    round_id: u64,
437    top_miner: Pubkey,
438    var_address: Pubkey,
439) -> Instruction {
440    reset_with_miners(signer, fee_collector, round_id, top_miner, var_address, &[])
441}
442
443pub fn reset_with_miners(
444    signer: Pubkey,
445    fee_collector: Pubkey,
446    round_id: u64,
447    top_miner: Pubkey,
448    var_address: Pubkey,
449    miner_accounts: &[Pubkey],
450) -> Instruction {
451    let board_address = board_pda().0;
452    let config_address = config_pda().0;
453    let mint_address = MINT_ADDRESS;
454    let round_address = round_pda(round_id).0;
455    let round_next_address = round_pda(round_id + 1).0;
456    let top_miner_address = miner_pda(top_miner).0;
457    let treasury_address = TREASURY_ADDRESS;
458    let treasury_tokens_address = treasury_tokens_address();
459    let pool_address = pool_pda().0;
460    let mint_authority_address = oil_mint_api::state::authority_pda().0;
461    let mut reset_instruction = Instruction {
462        program_id: crate::ID,
463        accounts: vec![
464            AccountMeta::new(signer, true),
465            AccountMeta::new(board_address, false),
466            AccountMeta::new(config_address, false),
467            AccountMeta::new(fee_collector, false),
468            AccountMeta::new(mint_address, false),
469            AccountMeta::new(round_address, false),
470            AccountMeta::new(round_next_address, false),
471            AccountMeta::new(top_miner_address, false),
472            AccountMeta::new(treasury_address, false),
473            AccountMeta::new(pool_address, false),
474            AccountMeta::new(treasury_tokens_address, false),
475            AccountMeta::new_readonly(system_program::ID, false),
476            AccountMeta::new_readonly(spl_token::ID, false),
477            AccountMeta::new_readonly(crate::ID, false),
478            AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
479            AccountMeta::new_readonly(SOL_MINT, false),
480            // Entropy accounts (these are in "other_accounts" after the split)
481            AccountMeta::new(var_address, false),
482            AccountMeta::new_readonly(entropy_rng_api::ID, false),
483            // Mint accounts.
484            AccountMeta::new(mint_authority_address, false),
485            AccountMeta::new_readonly(oil_mint_api::ID, false),
486        ],
487        data: Reset {}.to_bytes(),
488    };
489    
490    // Add miner accounts for seeker rewards (optional)
491    for miner_pubkey in miner_accounts {
492        reset_instruction.accounts.push(AccountMeta::new(
493            miner_pda(*miner_pubkey).0,
494            false,
495        ));
496    }
497    
498    reset_instruction
499}
500    
501// let [signer_info, automation_info, board_info, miner_info, round_info, treasury_info, system_program] =
502
503pub fn checkpoint(signer: Pubkey, authority: Pubkey, round_id: u64) -> Instruction {
504    let miner_address = miner_pda(authority).0;
505    let board_address = board_pda().0;
506    let round_address = round_pda(round_id).0;
507    let treasury_address = TREASURY_ADDRESS;
508    Instruction {
509        program_id: crate::ID,
510        accounts: vec![
511            AccountMeta::new(signer, true), // payer (session payer or regular wallet, receives bot fee)
512            AccountMeta::new(authority, false), // authority (user's wallet, for PDA derivation - must be writable when combined with deploy)
513            AccountMeta::new(board_address, false),
514            AccountMeta::new(miner_address, false),
515            AccountMeta::new(round_address, false),
516            AccountMeta::new(treasury_address, false),
517            AccountMeta::new_readonly(system_program::ID, false),
518        ],
519        data: Checkpoint {}.to_bytes(),
520    }
521}
522
523pub fn set_admin(signer: Pubkey, admin: Pubkey) -> Instruction {
524    let config_address = config_pda().0;
525    Instruction {
526        program_id: crate::ID,
527        accounts: vec![
528            AccountMeta::new(signer, true),
529            AccountMeta::new(config_address, false),
530            AccountMeta::new_readonly(system_program::ID, false),
531        ],
532        data: SetAdmin {
533            admin: admin.to_bytes(),
534        }
535        .to_bytes(),
536    }
537}
538
539pub fn set_admin_fee(signer: Pubkey, admin_fee: u64) -> Instruction {
540    let config_address = config_pda().0;
541    Instruction {
542        program_id: crate::ID,
543        accounts: vec![
544            AccountMeta::new(signer, true),
545            AccountMeta::new(config_address, false),
546            AccountMeta::new_readonly(system_program::ID, false),
547        ],
548        data: SetAdminFee {
549            admin_fee: admin_fee.to_le_bytes(),
550        }
551        .to_bytes(),
552    }
553}
554
555pub fn set_fee_collector(signer: Pubkey, fee_collector: Pubkey) -> Instruction {
556    let config_address = config_pda().0;
557    Instruction {
558        program_id: crate::ID,
559        accounts: vec![
560            AccountMeta::new(signer, true),
561            AccountMeta::new(config_address, false),
562            AccountMeta::new_readonly(system_program::ID, false),
563        ],
564        data: SetFeeCollector {
565            fee_collector: fee_collector.to_bytes(),
566        }
567        .to_bytes(),
568    }
569}
570
571/// Sets the TGE (Token Generation Event) timestamp.
572/// If current time < tge_timestamp, pre-mine is active.
573/// Set to 0 to disable pre-mine.
574/// Admin-only instruction.
575pub fn set_tge_timestamp(signer: Pubkey, tge_timestamp: i64) -> Instruction {
576    let config_address = config_pda().0;
577    Instruction {
578        program_id: crate::ID,
579        accounts: vec![
580            AccountMeta::new(signer, true),
581            AccountMeta::new(config_address, false),
582            AccountMeta::new_readonly(system_program::ID, false),
583        ],
584        data: SetTgeTimestamp {
585            tge_timestamp: tge_timestamp.to_le_bytes(),
586        }
587        .to_bytes(),
588    }
589}
590
591pub fn set_auction(
592    signer: Pubkey,
593    halving_period_seconds: u64,
594    last_halving_time: u64,
595    base_mining_rates: [u64; 4],
596    auction_duration_seconds: u64,
597    starting_prices: [u64; 4],
598    _well_id: u64, // Kept for backwards compatibility, but not used (always updates auction only)
599) -> Instruction {
600    let config_address = config_pda().0;
601    let auction_address = auction_pda().0;
602    
603    Instruction {
604        program_id: crate::ID,
605        accounts: vec![
606            AccountMeta::new(signer, true),
607            AccountMeta::new_readonly(config_address, false),
608            AccountMeta::new(auction_address, false),
609        ],
610        data: SetAuction {
611            halving_period_seconds: halving_period_seconds.to_le_bytes(),
612            last_halving_time: last_halving_time.to_le_bytes(),
613            base_mining_rates: [
614                base_mining_rates[0].to_le_bytes(),
615                base_mining_rates[1].to_le_bytes(),
616                base_mining_rates[2].to_le_bytes(),
617                base_mining_rates[3].to_le_bytes(),
618            ],
619            auction_duration_seconds: auction_duration_seconds.to_le_bytes(),
620            starting_prices: [
621                starting_prices[0].to_le_bytes(),
622                starting_prices[1].to_le_bytes(),
623                starting_prices[2].to_le_bytes(),
624                starting_prices[3].to_le_bytes(),
625            ],
626            well_id: 4u64.to_le_bytes(), // Always use 4 to indicate auction-only update
627        }
628        .to_bytes(),
629    }
630}
631
632// let [signer_info, mint_info, sender_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] =
633
634pub fn deposit(signer: Pubkey, authority: Pubkey, amount: u64, lock_duration_days: u64, stake_id: u64) -> Instruction {
635    let mint_address = MINT_ADDRESS;
636    let stake_address = stake_pda_with_id(authority, stake_id).0; // Derive from authority, not signer
637    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
638    let sender_address = get_associated_token_address(&authority, &MINT_ADDRESS); // Authority's ATA
639    let pool_address = pool_pda().0;
640    let pool_tokens_address = pool_tokens_address();
641    let miner_address = miner_pda(authority).0; // Derive from authority
642    Instruction {
643        program_id: crate::ID,
644        accounts: vec![
645            AccountMeta::new(signer, true), // payer (session payer or regular wallet, pays fees)
646            AccountMeta::new(authority, true), // authority (user's wallet, signs token transfer and used for PDA derivation)
647            AccountMeta::new(mint_address, false),
648            AccountMeta::new(sender_address, false),
649            AccountMeta::new(stake_address, false),
650            AccountMeta::new(stake_tokens_address, false),
651            AccountMeta::new(pool_address, false),
652            AccountMeta::new(pool_tokens_address, false),
653            AccountMeta::new(miner_address, false),
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: Deposit {
659            amount: amount.to_le_bytes(),
660            lock_duration_days: lock_duration_days.to_le_bytes(),
661            stake_id: stake_id.to_le_bytes(),
662        }
663        .to_bytes(),
664    }
665}
666
667// let [signer_info, mint_info, recipient_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] =
668
669pub fn withdraw(signer: Pubkey, authority: Pubkey, amount: u64, stake_id: u64) -> Instruction {
670    let stake_address = stake_pda_with_id(authority, stake_id).0; // Derive from authority, not signer
671    let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS);
672    let mint_address = MINT_ADDRESS;
673    let recipient_address = get_associated_token_address(&authority, &MINT_ADDRESS); // Authority's ATA
674    let pool_address = pool_pda().0;
675    let pool_tokens_address = pool_tokens_address();
676    let miner_address = miner_pda(authority).0; // Derive from authority
677    Instruction {
678        program_id: crate::ID,
679        accounts: vec![
680            AccountMeta::new(signer, true), // payer (session payer or regular wallet)
681            AccountMeta::new(authority, false), // authority (user's wallet, for PDA derivation)
682            AccountMeta::new(mint_address, false),
683            AccountMeta::new(recipient_address, false),
684            AccountMeta::new(stake_address, false),
685            AccountMeta::new(stake_tokens_address, false),
686            AccountMeta::new(pool_address, false),
687            AccountMeta::new(pool_tokens_address, false),
688            AccountMeta::new(miner_address, false),
689            AccountMeta::new_readonly(system_program::ID, false),
690            AccountMeta::new_readonly(spl_token::ID, false),
691            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
692        ],
693        data: Withdraw {
694            amount: amount.to_le_bytes(),
695            stake_id: stake_id.to_le_bytes(),
696        }
697        .to_bytes(),
698    }
699}
700
701// let [signer_info, automation_info, miner_info, system_program] = accounts else {
702
703/// Reload SOL from miner account to automation balance with single-tier referral system.
704/// 
705/// If the miner has a referrer, 1.0% of the claim goes to the referrer.
706/// 
707/// Account structure:
708/// - Base: signer, automation, miner, system_program
709/// - If miner has referrer (required): [miner_referrer, referral_referrer]
710pub fn reload_sol(
711    signer: Pubkey,
712    authority: Pubkey,
713    referrer_miner: Option<Pubkey>,
714    referrer_referral: Option<Pubkey>,
715) -> Instruction {
716    let automation_address = automation_pda(authority).0;
717    let miner_address = miner_pda(authority).0;
718    
719    let mut accounts = vec![
720        AccountMeta::new(signer, true),
721        AccountMeta::new(automation_address, false),
722        AccountMeta::new(miner_address, false),
723        AccountMeta::new_readonly(system_program::ID, false),
724    ];
725    
726    // Add referral accounts if provided (required when miner has referrer)
727    if let (Some(miner_ref), Some(referral_ref)) = (referrer_miner, referrer_referral) {
728        accounts.push(AccountMeta::new(miner_ref, false));
729        accounts.push(AccountMeta::new(referral_ref, false));
730    }
731    
732    Instruction {
733        program_id: crate::ID,
734        accounts,
735        data: ReloadSOL {}.to_bytes(),
736    }
737}
738
739// let [signer_info, mint_info, recipient_info, stake_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] =
740
741/// Claim SOL yield from staking. Stakers earn SOL rewards (2% of round winnings), not OIL.
742pub fn claim_yield(signer: Pubkey, authority: Pubkey, amount: u64, stake_id: u64) -> Instruction {
743    let stake_address = stake_pda_with_id(authority, stake_id).0; // Derive from authority, not signer
744    let pool_address = pool_pda().0;
745    Instruction {
746        program_id: crate::ID,
747        accounts: vec![
748            AccountMeta::new(signer, true), // payer (session payer or regular wallet)
749            AccountMeta::new(authority, true), // authority (user's wallet, receives SOL and used for PDA derivation)
750            AccountMeta::new(stake_address, false),
751            AccountMeta::new(pool_address, false),
752            AccountMeta::new_readonly(system_program::ID, false),
753        ],
754        data: ClaimYield {
755            amount: amount.to_le_bytes(),
756        }
757        .to_bytes(),
758    }
759}
760
761pub fn new_var(
762    signer: Pubkey,
763    provider: Pubkey,
764    id: u64,
765    commit: [u8; 32],
766    samples: u64,
767) -> Instruction {
768    let board_address = board_pda().0;
769    let config_address = config_pda().0;
770    let var_address = entropy_rng_api::state::var_pda(board_address, id).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(provider, false),
778            AccountMeta::new(var_address, false),
779            AccountMeta::new_readonly(system_program::ID, false),
780            AccountMeta::new_readonly(entropy_rng_api::ID, false),
781        ],
782        data: NewVar {
783            id: id.to_le_bytes(),
784            commit: commit,
785            samples: samples.to_le_bytes(),
786        }
787        .to_bytes(),
788    }
789}
790
791pub fn set_swap_program(signer: Pubkey, new_program: Pubkey) -> Instruction {
792    let config_address = config_pda().0;
793    Instruction {
794        program_id: crate::ID,
795        accounts: vec![
796            AccountMeta::new(signer, true),
797            AccountMeta::new(config_address, false),
798            AccountMeta::new_readonly(new_program, false),
799        ],
800        data: SetSwapProgram {}.to_bytes(),
801    }
802}
803
804pub fn set_var_address(signer: Pubkey, new_var_address: Pubkey) -> Instruction {
805    let board_address = board_pda().0;
806    let config_address = config_pda().0;
807    Instruction {
808        program_id: crate::ID,
809        accounts: vec![
810            AccountMeta::new(signer, true),
811            AccountMeta::new(board_address, false),
812            AccountMeta::new(config_address, false),
813            AccountMeta::new(new_var_address, false),
814        ],
815        data: SetVarAddress {}.to_bytes(),
816    }
817}
818
819/// Migrate: Extend Config struct with tge_timestamp field.
820/// This migration ensures the Config account has the new tge_timestamp field available.
821/// Must be called by the admin.
822/// Accounts: signer, config, system_program
823pub fn migrate(signer: Pubkey) -> Instruction {
824    let config_address = config_pda().0;
825    Instruction {
826        program_id: crate::ID,
827        accounts: vec![
828            AccountMeta::new(signer, true),
829            AccountMeta::new(config_address, false),
830            AccountMeta::new_readonly(system_program::ID, false),
831        ],
832        data: Migrate {}.to_bytes(),
833    }
834}
835
836/// Create a referral account to become a referrer.
837pub fn create_referral(signer: Pubkey) -> Instruction {
838    let referral_address = referral_pda(signer).0;
839    Instruction {
840        program_id: crate::ID,
841        accounts: vec![
842            AccountMeta::new(signer, true),
843            AccountMeta::new(referral_address, false),
844            AccountMeta::new_readonly(system_program::ID, false),
845        ],
846        data: CreateReferral {}.to_bytes(),
847    }
848}
849
850/// Creates a Code account linking an access code to a specific wallet (authority).
851/// Admin-only instruction.
852/// Accounts: signer (admin), config, code, system_program
853pub fn create_code(
854    signer: Pubkey,
855    code_hash: [u8; 32],
856    authority: Pubkey,
857) -> Instruction {
858    let config_address = config_pda().0;
859    let (code_address, _) = Code::pda(code_hash, authority);
860    Instruction {
861        program_id: crate::ID,
862        accounts: vec![
863            AccountMeta::new(signer, true), // signer (admin)
864            AccountMeta::new_readonly(config_address, false), // config
865            AccountMeta::new(code_address, false), // code
866            AccountMeta::new_readonly(system_program::ID, false), // system_program
867        ],
868        data: CreateCode {
869            code_hash,
870            authority: authority.to_bytes(),
871        }
872        .to_bytes(),
873    }
874}
875
876/// Claim pending referral rewards (both SOL and OIL).
877/// 
878/// Account structure (for Fogo sessions):
879/// - Base: signer (payer), authority (user's wallet), referral, referral_tokens, mint, recipient, system_program, token_program, associated_token_program
880pub fn claim_referral(signer: Pubkey, authority: Pubkey) -> Instruction {
881    let referral_address = referral_pda(authority).0;
882    let referral_oil_address = get_associated_token_address(&referral_address, &MINT_ADDRESS);
883    let recipient_oil_address = get_associated_token_address(&authority, &MINT_ADDRESS);
884    Instruction {
885        program_id: crate::ID,
886        accounts: vec![
887            AccountMeta::new(signer, true), // 0: signer (payer)
888            AccountMeta::new(authority, false), // 1: authority (user's wallet, receives SOL)
889            AccountMeta::new(referral_address, false), // 2: referral
890            AccountMeta::new(referral_oil_address, false), // 3: referral_tokens (Referral account's OIL ATA)
891            AccountMeta::new(MINT_ADDRESS, false), // 4: mint
892            AccountMeta::new(recipient_oil_address, false), // 5: recipient (Recipient's OIL ATA - authority's wallet)
893            AccountMeta::new_readonly(system_program::ID, false), // 6: system_program
894            AccountMeta::new_readonly(spl_token::ID, false), // 7: token_program
895            AccountMeta::new_readonly(spl_associated_token_account::ID, false), // 8: associated_token_program
896        ],
897        data: ClaimReferral {}.to_bytes(),
898    }
899}
900
901/// Direct solo bid on an auction well (seize ownership).
902/// The bid amount is calculated on-chain as current_price + 1 lamport.
903/// User must have enough SOL in their wallet to cover the bid.
904/// 
905/// Account structure:
906/// - Base: signer, square, fund (optional), auction, treasury, treasury_tokens, mint, mint_authority, mint_program, staking_pool, fee_collector, config, token_program, system_program
907/// - If previous owner exists (optional): [previous_owner_miner, previous_owner]
908pub fn place_bid(
909    signer: Pubkey,
910    square_id: u64,
911    fee_collector: Pubkey,
912    pool_account: Option<Pubkey>, // Pool account for current epoch (optional, if pool exists)
913    previous_owner_miner: Option<Pubkey>, // Previous owner's miner PDA (if previous owner exists)
914    previous_owner: Option<Pubkey>, // Previous owner pubkey (if previous owner exists)
915    referrer: Option<Pubkey>, // Optional referrer pubkey for new miners
916) -> Instruction {
917    let well_address = well_pda(square_id).0;
918    let auction_address = auction_pda().0;
919    let treasury_address = treasury_pda().0;
920    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
921    let staking_pool_address = pool_pda().0;
922    let config_address = config_pda().0;
923    let mint_authority_address = oil_mint_api::state::authority_pda().0;
924    
925    let mut accounts = vec![
926        AccountMeta::new(signer, true),
927        AccountMeta::new(well_address, false),
928    ];
929    
930    // Add pool account if provided (for current epoch)
931    if let Some(pool_pubkey) = pool_account {
932        accounts.push(AccountMeta::new(pool_pubkey, false));
933    } else {
934        // Add placeholder (account order must be consistent)
935        accounts.push(AccountMeta::new_readonly(system_program::ID, false)); // Placeholder, will be ignored
936    }
937    
938    accounts.extend_from_slice(&[
939        AccountMeta::new(auction_address, false), // Must be writable for auction_program_log CPI
940        AccountMeta::new(treasury_address, false),
941        AccountMeta::new(treasury_tokens_address, false),
942        AccountMeta::new(MINT_ADDRESS, false),
943        AccountMeta::new(mint_authority_address, false),
944        AccountMeta::new_readonly(oil_mint_api::ID, false),
945        AccountMeta::new(staking_pool_address, false),
946        AccountMeta::new(fee_collector, false),
947        AccountMeta::new(config_address, false),
948        AccountMeta::new_readonly(spl_token::ID, false),
949        AccountMeta::new_readonly(system_program::ID, false),
950        AccountMeta::new_readonly(crate::ID, false), // oil_program
951    ]);
952    
953    // Add previous owner accounts if provided
954    if let (Some(miner_pubkey), Some(owner_pubkey)) = (previous_owner_miner, previous_owner) {
955        accounts.push(AccountMeta::new(miner_pubkey, false));
956        accounts.push(AccountMeta::new(owner_pubkey, false));
957    }
958    
959    // Add referral account if referrer is provided
960    if let Some(referrer_pubkey) = referrer {
961        let referral_address = referral_pda(referrer_pubkey).0;
962        accounts.push(AccountMeta::new(referral_address, false));
963    }
964    
965    Instruction {
966        program_id: crate::ID,
967        accounts,
968        data: instruction::PlaceBid {
969            square_id: square_id.to_le_bytes(),
970            referrer: referrer.unwrap_or(Pubkey::default()).to_bytes(),
971        }
972        .to_bytes(),
973    }
974}
975
976/// Claim auction-based OIL rewards
977/// - OIL rewards: from current ownership and previous ownership (pre-minted)
978/// 
979/// Account structure:
980/// - 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
981/// - 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)
982pub fn claim_auction_oil(
983    signer: Pubkey,
984    well_mask: u8, // Bitmask: bit 0 = well 0, bit 1 = well 1, etc.
985    well_accounts: [Option<Pubkey>; 4], // Well PDAs for wells 0-3 (required for wells in mask)
986    auction_pool_accounts: Option<[Option<Pubkey>; 4]>, // Auction Pool PDAs for wells 0-3 (optional, for pool contributors)
987    bid_accounts: Option<[Option<Pubkey>; 4]>, // Bid PDAs for wells 0-3 (required for pool contributors, must include epoch_id in PDA)
988) -> Instruction {
989    let miner_address = miner_pda(signer).0;
990    let auction_address = auction_pda().0;
991    let treasury_address = treasury_pda().0;
992    let treasury_tokens_address = get_associated_token_address(&treasury_address, &MINT_ADDRESS);
993    let recipient_address = get_associated_token_address(&signer, &MINT_ADDRESS);
994    let mint_authority_address = oil_mint_api::state::authority_pda().0;
995    
996    let mut accounts = vec![
997        AccountMeta::new(signer, true),
998        AccountMeta::new(miner_address, false),
999    ];
1000    
1001    // Add well accounts for wells in mask (all 4 required, but only wells in mask are used)
1002    for well_opt in well_accounts.iter() {
1003        if let Some(well_pubkey) = well_opt {
1004            accounts.push(AccountMeta::new(*well_pubkey, false));
1005        } else {
1006            // Use a placeholder account if well is not provided
1007            accounts.push(AccountMeta::new_readonly(system_program::ID, false));
1008        }
1009    }
1010    
1011    // Add auction pool accounts if provided (optional, for pool contributors)
1012    if let Some(auction_pool_pdas) = auction_pool_accounts {
1013        for auction_pool_pda_opt in auction_pool_pdas.iter() {
1014            if let Some(auction_pool_pubkey) = auction_pool_pda_opt {
1015                accounts.push(AccountMeta::new(*auction_pool_pubkey, false));
1016            } else {
1017                // Use a placeholder account if auction pool is not provided
1018                accounts.push(AccountMeta::new_readonly(system_program::ID, false));
1019            }
1020        }
1021    } else {
1022        // Add 4 placeholder accounts if auction_pool_accounts is None
1023        for _ in 0..4 {
1024            accounts.push(AccountMeta::new_readonly(system_program::ID, false));
1025        }
1026    }
1027    
1028    accounts.extend_from_slice(&[
1029        AccountMeta::new(auction_address, false), // Must be writable for auction_program_log CPI
1030        AccountMeta::new(treasury_address, false),
1031        AccountMeta::new(treasury_tokens_address, false),
1032        AccountMeta::new(MINT_ADDRESS, false), // Must be writable for mint_oil CPI
1033        AccountMeta::new(mint_authority_address, false), // Must be writable for mint_oil CPI
1034        AccountMeta::new_readonly(oil_mint_api::ID, false),
1035        AccountMeta::new(recipient_address, false),
1036        AccountMeta::new_readonly(spl_token::ID, false),
1037        AccountMeta::new_readonly(spl_associated_token_account::ID, false),
1038        AccountMeta::new_readonly(system_program::ID, false),
1039        AccountMeta::new_readonly(crate::ID, false), // oil_program
1040    ]);
1041    
1042    // Add bid accounts if provided (for pool contributors)
1043    if let Some(bid_pdas) = bid_accounts {
1044        for bid_pda_opt in bid_pdas.iter() {
1045            if let Some(bid_pubkey) = bid_pda_opt {
1046                accounts.push(AccountMeta::new(*bid_pubkey, false));
1047            }
1048        }
1049    }
1050    
1051    Instruction {
1052        program_id: crate::ID,
1053        accounts,
1054        data: ClaimAuctionOIL {
1055            well_mask,
1056        }
1057        .to_bytes(),
1058    }
1059}
1060
1061/// Claim auction-based SOL rewards
1062/// - SOL rewards: from being outbid and refunds from abandoned pools
1063/// 
1064/// Account structure:
1065/// - Base: signer, miner, well accounts (one per well 0-3, for checking abandoned pools), auction pool accounts (optional, one per well), auction, treasury, system_program, oil_program
1066/// - Bid accounts (one per well, required for refunds): [bid_0, bid_1, bid_2, bid_3] (must include epoch_id in PDA)
1067pub fn claim_auction_sol(
1068    signer: Pubkey,
1069    well_accounts: [Option<Pubkey>; 4], // Well PDAs for wells 0-3 (for checking abandoned pools)
1070    auction_pool_accounts: Option<[Option<Pubkey>; 4]>, // Auction Pool PDAs for wells 0-3 (optional, for refunds)
1071    bid_accounts: Option<[Option<Pubkey>; 4]>, // Bid PDAs for wells 0-3 (required for refunds, must include epoch_id in PDA)
1072) -> Instruction {
1073    let miner_address = miner_pda(signer).0;
1074    let (auction_address, _) = auction_pda();
1075    let treasury_address = treasury_pda().0;
1076    
1077    let mut accounts = vec![
1078        AccountMeta::new(signer, true),
1079        AccountMeta::new(miner_address, false),
1080    ];
1081    
1082    // Add well accounts (all 4 wells for checking abandoned pools)
1083    for well_opt in well_accounts.iter() {
1084        if let Some(well_pubkey) = well_opt {
1085            accounts.push(AccountMeta::new(*well_pubkey, false));
1086        } else {
1087            // Use a placeholder account if well is not provided
1088            accounts.push(AccountMeta::new_readonly(system_program::ID, false));
1089        }
1090    }
1091    
1092    // Add auction pool accounts if provided (optional, for refunds)
1093    if let Some(auction_pool_pdas) = auction_pool_accounts {
1094        for auction_pool_pda_opt in auction_pool_pdas.iter() {
1095            if let Some(auction_pool_pubkey) = auction_pool_pda_opt {
1096                accounts.push(AccountMeta::new(*auction_pool_pubkey, false));
1097            } else {
1098                // Use a placeholder account if auction pool is not provided
1099                accounts.push(AccountMeta::new_readonly(system_program::ID, false));
1100            }
1101        }
1102    } else {
1103        // Add 4 placeholder accounts if auction_pool_accounts is None
1104        for _ in 0..4 {
1105            accounts.push(AccountMeta::new_readonly(system_program::ID, false));
1106        }
1107    }
1108    
1109    accounts.extend_from_slice(&[
1110        AccountMeta::new(auction_address, false), // Must be writable for auction_program_log CPI
1111        AccountMeta::new(treasury_address, false),
1112        AccountMeta::new_readonly(system_program::ID, false),
1113        AccountMeta::new_readonly(crate::ID, false), // oil_program
1114    ]);
1115    
1116    // Add bid accounts if provided (for refunds)
1117    if let Some(bid_pdas) = bid_accounts {
1118        for bid_pda_opt in bid_pdas.iter() {
1119            if let Some(bid_pubkey) = bid_pda_opt {
1120                accounts.push(AccountMeta::new(*bid_pubkey, false));
1121            }
1122        }
1123    }
1124    
1125    Instruction {
1126        program_id: crate::ID,
1127        accounts,
1128        data: ClaimAuctionSOL {
1129            _reserved: 0,
1130        }
1131        .to_bytes(),
1132    }
1133}
1134
1135pub fn claim_seeker(signer: Pubkey, mint: Pubkey) -> Instruction {
1136    let seeker_address = seeker_pda(mint).0;
1137    let token_account_address = get_associated_token_address(&signer, &mint);
1138    Instruction {
1139        program_id: crate::ID,
1140        accounts: vec![
1141            AccountMeta::new(signer, true),
1142            AccountMeta::new_readonly(mint, false),
1143            AccountMeta::new(seeker_address, false),
1144            AccountMeta::new(token_account_address, false),
1145            AccountMeta::new_readonly(system_program::ID, false),
1146        ],
1147        data: ClaimSeeker {}.to_bytes(),
1148    }
1149}