Skip to main content

satrush_client/
builders.rs

1//! Environment-free instruction builders.
2//!
3//! Thin composition helpers over the generated instruction structs: they derive
4//! every PDA and associated token account from the program's fixed seeds, so a
5//! caller only supplies the signing authority and the mint addresses. Shared by
6//! the LiteSVM test-suite and the `satrush-cli` binary.
7
8use crate::instructions::{
9    CancelPublicAutomation, ClaimUsd, ClaimUsdInstructionArgs, CloseRound, CreateBoard, CreateEpochVault,
10    CreateOneBtcVault, CreatePublicAutomation, CreatePublicAutomationInstructionArgs, CreateSatrushConfig,
11    CreateSatrushConfigInstructionArgs, CreateSatsVault, CreateTreasury, DeployPublic, DeployPublicInstructionArgs,
12    ExecutePublicAutomation, ExecutePublicAutomationInstructionArgs, RotateRound, SettleDeployPublic, SwapRoundStake,
13    SwapRoundStakeInstructionArgs, TopUpPublicAutomation, TopUpPublicAutomationInstructionArgs,
14    UpdateBoardRoundDuration, UpdateBoardRoundDurationInstructionArgs, UpdateDeployFees,
15    UpdateDeployFeesInstructionArgs, UpdateDeploymentSettleGraceDuration,
16    UpdateDeploymentSettleGraceDurationInstructionArgs, UpdateEpochVaultIterationDuration,
17    UpdateEpochVaultIterationDurationInstructionArgs, UpdateMinDeployUsdAmount,
18    UpdateMinDeployUsdAmountInstructionArgs, UpdateStrikeTriggerModulus, UpdateStrikeTriggerModulusInstructionArgs,
19    UpdateUnclaimedHashrateBps, UpdateUnclaimedHashrateBpsInstructionArgs,
20};
21use crate::types::AutomationStrategy;
22use crate::{
23    get_board_address, get_epoch_vault_address, get_epoch_vault_iteration_address, get_event_authority_address,
24    get_miner_address, get_one_btc_vault_address, get_one_btc_vault_iteration_address, get_public_automation_address,
25    get_public_deployment_address, get_round_address, get_satrush_config_address, get_sats_vault_address,
26    get_treasury_address,
27};
28use solana_instruction::{AccountMeta, Instruction};
29use solana_pubkey::Pubkey;
30
31/// SPL Token program.
32pub const TOKEN_PROGRAM_ID: Pubkey = Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
33/// SPL Associated Token Account program.
34pub const ASSOCIATED_TOKEN_PROGRAM_ID: Pubkey = Pubkey::from_str_const("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
35/// System program.
36pub const SYSTEM_PROGRAM_ID: Pubkey = Pubkey::from_str_const("11111111111111111111111111111111");
37/// SlotHashes sysvar.
38pub const SLOT_HASHES_ID: Pubkey = Pubkey::from_str_const("SysvarS1otHashes111111111111111111111111111");
39
40/// Derive the canonical associated token account for `wallet` holding `mint`.
41pub fn get_associated_token_address(wallet: &Pubkey, mint: &Pubkey) -> Pubkey {
42    Pubkey::find_program_address(
43        &[wallet.as_ref(), TOKEN_PROGRAM_ID.as_ref(), mint.as_ref()],
44        &ASSOCIATED_TOKEN_PROGRAM_ID,
45    )
46    .0
47}
48
49/// `create_satrush_config`: the config PDA holding authorities, mints and fee
50/// parameters. `authority` pays and must equal the program's upgrade authority.
51pub fn get_create_satrush_config_instruction(
52    authority: Pubkey,
53    args: CreateSatrushConfigInstructionArgs,
54) -> Instruction {
55    CreateSatrushConfig {
56        authority,
57        satrush_config: get_satrush_config_address().0,
58        system_program: SYSTEM_PROGRAM_ID,
59    }
60    .instruction(args)
61}
62
63/// `create_board`: the board singleton, its USD/BTC pools and the initial round
64/// (id 1). Signed by the config's admin authority.
65pub fn get_create_board_instruction(authority: Pubkey, usd_mint: Pubkey, btc_mint: Pubkey) -> Instruction {
66    let board = get_board_address().0;
67    CreateBoard {
68        authority,
69        satrush_config: get_satrush_config_address().0,
70        board,
71        initial_round: get_round_address(1).0,
72        usd_mint,
73        btc_mint,
74        board_usd_ata: get_associated_token_address(&board, &usd_mint),
75        board_btc_ata: get_associated_token_address(&board, &btc_mint),
76        token_program: TOKEN_PROGRAM_ID,
77        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
78        system_program: SYSTEM_PROGRAM_ID,
79    }
80    .instruction()
81}
82
83/// `update_board_round_duration`: overwrite the board's `round_duration` (slots).
84/// Applies to future round activations only; the active round keeps its window.
85/// Signed by the config's admin authority.
86pub fn get_update_board_round_duration_instruction(authority: Pubkey, new_round_duration: u32) -> Instruction {
87    UpdateBoardRoundDuration {
88        authority,
89        satrush_config: get_satrush_config_address().0,
90        board: get_board_address().0,
91    }
92    .instruction(UpdateBoardRoundDurationInstructionArgs { new_round_duration })
93}
94
95/// `update_min_deploy_usd_amount`: overwrite the config's minimum gross deploy
96/// size (USD mint base units). Applies to every subsequent manual deploy,
97/// automation creation and automation execution. Signed by the config's admin
98/// authority.
99pub fn get_update_min_deploy_usd_amount_instruction(authority: Pubkey, new_min_deploy_usd_amount: u64) -> Instruction {
100    UpdateMinDeployUsdAmount {
101        authority,
102        satrush_config: get_satrush_config_address().0,
103    }
104    .instruction(UpdateMinDeployUsdAmountInstructionArgs {
105        new_min_deploy_usd_amount,
106    })
107}
108
109/// `update_unclaimed_hashrate_bps`: overwrite the config's deferred hashrate
110/// bonus ratio (bps of each settled play's reward). Signed by the config's
111/// admin authority.
112pub fn get_update_unclaimed_hashrate_bps_instruction(
113    authority: Pubkey,
114    new_unclaimed_hashrate_bps: u32,
115) -> Instruction {
116    UpdateUnclaimedHashrateBps {
117        authority,
118        satrush_config: get_satrush_config_address().0,
119    }
120    .instruction(UpdateUnclaimedHashrateBpsInstructionArgs {
121        new_unclaimed_hashrate_bps,
122    })
123}
124
125/// `update_deploy_fees`: atomically overwrite the four deploy-time fee legs.
126/// Each leg must be at least 1 bps and the legs must sum to exactly 800 bps
127/// (8%); the split may vary but the total never changes. Signed by the
128/// config's admin authority.
129pub fn get_update_deploy_fees_instruction(
130    authority: Pubkey,
131    new_strike_fee_bps: u32,
132    new_epoch_fee_bps: u32,
133    new_one_btc_fee_bps: u32,
134    new_protocol_fee_bps: u32,
135) -> Instruction {
136    UpdateDeployFees {
137        authority,
138        satrush_config: get_satrush_config_address().0,
139    }
140    .instruction(UpdateDeployFeesInstructionArgs {
141        new_strike_fee_bps,
142        new_epoch_fee_bps,
143        new_one_btc_fee_bps,
144        new_protocol_fee_bps,
145    })
146}
147
148/// `update_epoch_vault_iteration_duration`: overwrite the config's epoch vault
149/// iteration length (slots). Applies to the currently accumulating iteration
150/// immediately. Signed by the config's admin authority.
151pub fn get_update_epoch_vault_iteration_duration_instruction(
152    authority: Pubkey,
153    new_iteration_duration: u64,
154) -> Instruction {
155    UpdateEpochVaultIterationDuration {
156        authority,
157        satrush_config: get_satrush_config_address().0,
158    }
159    .instruction(UpdateEpochVaultIterationDurationInstructionArgs { new_iteration_duration })
160}
161
162/// `update_strike_trigger_modulus`: admin retunes the Sat Strike odds (the
163/// jackpot fires when `rng % modulus == 0`). Signed by the config's admin
164/// authority.
165pub fn get_update_strike_trigger_modulus_instruction(authority: Pubkey, new_modulus: u16) -> Instruction {
166    UpdateStrikeTriggerModulus {
167        authority,
168        satrush_config: get_satrush_config_address().0,
169    }
170    .instruction(UpdateStrikeTriggerModulusInstructionArgs { new_modulus })
171}
172
173/// `update_deployment_settle_grace_duration`: admin retunes the settle grace
174/// window (slots after a round settles before stale deployments may be
175/// force-cleaned; 0 disables cleanup).
176pub fn get_update_deployment_settle_grace_duration_instruction(
177    authority: Pubkey,
178    new_grace_duration: u64,
179) -> Instruction {
180    UpdateDeploymentSettleGraceDuration {
181        authority,
182        satrush_config: get_satrush_config_address().0,
183    }
184    .instruction(UpdateDeploymentSettleGraceDurationInstructionArgs { new_grace_duration })
185}
186
187/// `create_epoch_vault`: the epoch vault singleton, its USD/BTC pools and the
188/// first iteration (id 1).
189pub fn get_create_epoch_vault_instruction(authority: Pubkey, usd_mint: Pubkey, btc_mint: Pubkey) -> Instruction {
190    let epoch_vault = get_epoch_vault_address().0;
191    CreateEpochVault {
192        authority,
193        satrush_config: get_satrush_config_address().0,
194        epoch_vault,
195        epoch_vault_iteration: get_epoch_vault_iteration_address(1).0,
196        usd_mint,
197        btc_mint,
198        epoch_vault_usd_ata: get_associated_token_address(&epoch_vault, &usd_mint),
199        epoch_vault_btc_ata: get_associated_token_address(&epoch_vault, &btc_mint),
200        token_program: TOKEN_PROGRAM_ID,
201        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
202        system_program: SYSTEM_PROGRAM_ID,
203    }
204    .instruction()
205}
206
207/// `create_one_btc_vault`: the 1 BTC vault singleton, its USD/BTC pools and the
208/// first iteration (id 1).
209pub fn get_create_one_btc_vault_instruction(authority: Pubkey, usd_mint: Pubkey, btc_mint: Pubkey) -> Instruction {
210    let one_btc_vault = get_one_btc_vault_address().0;
211    CreateOneBtcVault {
212        authority,
213        satrush_config: get_satrush_config_address().0,
214        one_btc_vault,
215        one_btc_vault_iteration: get_one_btc_vault_iteration_address(1).0,
216        usd_mint,
217        btc_mint,
218        one_btc_vault_usd_ata: get_associated_token_address(&one_btc_vault, &usd_mint),
219        one_btc_vault_btc_ata: get_associated_token_address(&one_btc_vault, &btc_mint),
220        token_program: TOKEN_PROGRAM_ID,
221        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
222        system_program: SYSTEM_PROGRAM_ID,
223    }
224    .instruction()
225}
226
227/// `create_treasury`: the treasury singleton and its USD fee pool.
228pub fn get_create_treasury_instruction(authority: Pubkey, usd_mint: Pubkey) -> Instruction {
229    let treasury = get_treasury_address().0;
230    CreateTreasury {
231        authority,
232        satrush_config: get_satrush_config_address().0,
233        treasury,
234        usd_mint,
235        treasury_usd_ata: get_associated_token_address(&treasury, &usd_mint),
236        token_program: TOKEN_PROGRAM_ID,
237        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
238        system_program: SYSTEM_PROGRAM_ID,
239    }
240    .instruction()
241}
242
243/// `deploy_public`: stake `amount` USD (base units; all fees are deducted from
244/// it, so the miner parts with exactly `amount`) on the tiles
245/// in `selection_mask` for round `round_id`, as the miner `authority`. The round
246/// must be the board's current one and open for deploys; the miner profile and
247/// deployment record PDAs are created by the instruction.
248pub fn get_deploy_public_instruction(
249    authority: Pubkey,
250    usd_mint: Pubkey,
251    round_id: u32,
252    selection_mask: u32,
253    amount: u64,
254) -> Instruction {
255    let board = get_board_address().0;
256
257    DeployPublic {
258        authority,
259        satrush_config: get_satrush_config_address().0,
260        board,
261        usd_mint,
262        board_usd_ata: get_associated_token_address(&board, &usd_mint),
263        authority_usd_ata: get_associated_token_address(&authority, &usd_mint),
264        round: get_round_address(round_id).0,
265        public_deployment: get_public_deployment_address(authority, round_id).0,
266        miner: get_miner_address(authority).0,
267        token_program: TOKEN_PROGRAM_ID,
268        system_program: SYSTEM_PROGRAM_ID,
269        event_authority: get_event_authority_address().0,
270        program: crate::SATRUSH_ID,
271    }
272    .instruction(DeployPublicInstructionArgs { selection_mask, amount })
273}
274
275/// `rotate_round`: reveal `current_round_id`'s winning tile, sweep the round's
276/// accumulated fee legs from the board pool to the epoch/1 BTC/treasury pools
277/// (plus, on a strike trigger, the strike skim's USD and BTC legs to the epoch
278/// vault), and deploy round `current_round_id + 1` as the board's new active
279/// round. Signed by the config's round authority; valid once the round's
280/// window elapsed.
281pub fn get_rotate_round_instruction(
282    authority: Pubkey,
283    usd_mint: Pubkey,
284    btc_mint: Pubkey,
285    current_round_id: u32,
286) -> Instruction {
287    let board = get_board_address().0;
288    let epoch_vault = get_epoch_vault_address().0;
289    let one_btc_vault = get_one_btc_vault_address().0;
290    let treasury = get_treasury_address().0;
291
292    RotateRound {
293        authority,
294        satrush_config: get_satrush_config_address().0,
295        board,
296        current_round: get_round_address(current_round_id).0,
297        next_round: get_round_address(current_round_id + 1).0,
298        usd_mint,
299        btc_mint,
300        board_usd_ata: get_associated_token_address(&board, &usd_mint),
301        board_btc_ata: get_associated_token_address(&board, &btc_mint),
302        epoch_vault,
303        epoch_vault_usd_ata: get_associated_token_address(&epoch_vault, &usd_mint),
304        epoch_vault_btc_ata: get_associated_token_address(&epoch_vault, &btc_mint),
305        one_btc_vault,
306        one_btc_vault_usd_ata: get_associated_token_address(&one_btc_vault, &usd_mint),
307        treasury,
308        treasury_usd_ata: get_associated_token_address(&treasury, &usd_mint),
309        slot_hashes: SLOT_HASHES_ID,
310        token_program: TOKEN_PROGRAM_ID,
311        system_program: SYSTEM_PROGRAM_ID,
312        event_authority: get_event_authority_address().0,
313        program: crate::SATRUSH_ID,
314    }
315    .instruction()
316}
317
318/// `swap_round_stake`: relay a pre-built aggregator route that converts part of
319/// the revealed round's USD into BTC. `swap_data` and `route_accounts` are the
320/// route's opaque instruction data and account list; the on-chain handler
321/// enforces the economics against observed balance deltas. Signed by the
322/// config's round authority.
323#[allow(clippy::too_many_arguments)]
324pub fn get_swap_round_stake_instruction(
325    authority: Pubkey,
326    usd_mint: Pubkey,
327    btc_mint: Pubkey,
328    round_id: u32,
329    min_btc_out: u64,
330    swap_program: Pubkey,
331    swap_data: Vec<u8>,
332    route_accounts: &[AccountMeta],
333) -> Instruction {
334    let board = get_board_address().0;
335    SwapRoundStake {
336        authority,
337        satrush_config: get_satrush_config_address().0,
338        board,
339        round: get_round_address(round_id).0,
340        usd_mint,
341        btc_mint,
342        board_usd_ata: get_associated_token_address(&board, &usd_mint),
343        board_btc_ata: get_associated_token_address(&board, &btc_mint),
344        swap_program,
345        token_program: TOKEN_PROGRAM_ID,
346        event_authority: get_event_authority_address().0,
347        program: crate::SATRUSH_ID,
348    }
349    .instruction_with_remaining_accounts(SwapRoundStakeInstructionArgs { min_btc_out, swap_data }, route_accounts)
350}
351
352/// `settle_deploy_public`: settle `deployment_authority`'s deployment in a
353/// Settled round. `authority` signs (the owner, or the round authority for
354/// automated deployments); `rent_recipient` must be the round authority for
355/// automated deployments and the owner for manual ones.
356pub fn get_settle_deploy_public_instruction(
357    authority: Pubkey,
358    deployment_authority: Pubkey,
359    rent_recipient: Pubkey,
360    usd_mint: Pubkey,
361    btc_mint: Pubkey,
362    round_id: u32,
363) -> Instruction {
364    let board = get_board_address().0;
365    let sats_vault = get_sats_vault_address().0;
366    let public_automation = get_public_automation_address(deployment_authority).0;
367    SettleDeployPublic {
368        authority,
369        rent_recipient,
370        satrush_config: get_satrush_config_address().0,
371        round: get_round_address(round_id).0,
372        board,
373        public_deployment: get_public_deployment_address(deployment_authority, round_id).0,
374        miner: get_miner_address(deployment_authority).0,
375        public_automation,
376        automation_usd_ata: get_associated_token_address(&public_automation, &usd_mint),
377        board_usd_ata: get_associated_token_address(&board, &usd_mint),
378        sats_vault,
379        btc_mint,
380        usd_mint,
381        board_btc_ata: get_associated_token_address(&board, &btc_mint),
382        sats_vault_btc_ata: get_associated_token_address(&sats_vault, &btc_mint),
383        token_program: TOKEN_PROGRAM_ID,
384        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
385        system_program: SYSTEM_PROGRAM_ID,
386        event_authority: get_event_authority_address().0,
387        program: crate::SATRUSH_ID,
388    }
389    .instruction()
390}
391
392/// `create_public_automation`: escrow `deposit_usd_amount` and configure the
393/// crank to deploy `per_round_usd_amount` per round with the given strategy.
394/// One automation per authority.
395#[allow(clippy::too_many_arguments)]
396pub fn get_create_public_automation_instruction(
397    authority: Pubkey,
398    usd_mint: Pubkey,
399    strategy: AutomationStrategy,
400    selection_mask: u32,
401    per_round_usd_amount: u64,
402    reload: bool,
403    deposit_usd_amount: u64,
404) -> Instruction {
405    let public_automation = get_public_automation_address(authority).0;
406    CreatePublicAutomation {
407        authority,
408        satrush_config: get_satrush_config_address().0,
409        public_automation,
410        usd_mint,
411        authority_usd_ata: get_associated_token_address(&authority, &usd_mint),
412        automation_usd_ata: get_associated_token_address(&public_automation, &usd_mint),
413        miner: get_miner_address(authority).0,
414        token_program: TOKEN_PROGRAM_ID,
415        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
416        system_program: SYSTEM_PROGRAM_ID,
417    }
418    .instruction(CreatePublicAutomationInstructionArgs {
419        strategy,
420        selection_mask,
421        per_round_usd_amount,
422        reload,
423        deposit_usd_amount,
424    })
425}
426
427/// `top_up_public_automation`: move `amount` USD from the authority's account
428/// into the automation's escrow.
429pub fn get_top_up_public_automation_instruction(authority: Pubkey, usd_mint: Pubkey, amount: u64) -> Instruction {
430    let public_automation = get_public_automation_address(authority).0;
431    TopUpPublicAutomation {
432        authority,
433        satrush_config: get_satrush_config_address().0,
434        public_automation,
435        usd_mint,
436        authority_usd_ata: get_associated_token_address(&authority, &usd_mint),
437        automation_usd_ata: get_associated_token_address(&public_automation, &usd_mint),
438        token_program: TOKEN_PROGRAM_ID,
439    }
440    .instruction(TopUpPublicAutomationInstructionArgs { amount })
441}
442
443/// `cancel_public_automation`: refund the full escrow balance and close the
444/// automation and its token account. Unconditional; in-flight deployments
445/// settle to the miner profile later.
446pub fn get_cancel_public_automation_instruction(authority: Pubkey, usd_mint: Pubkey) -> Instruction {
447    let public_automation = get_public_automation_address(authority).0;
448    CancelPublicAutomation {
449        authority,
450        satrush_config: get_satrush_config_address().0,
451        public_automation,
452        usd_mint,
453        automation_usd_ata: get_associated_token_address(&public_automation, &usd_mint),
454        authority_usd_ata: get_associated_token_address(&authority, &usd_mint),
455        token_program: TOKEN_PROGRAM_ID,
456        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
457        system_program: SYSTEM_PROGRAM_ID,
458    }
459    .instruction()
460}
461
462/// `execute_public_automation`: crank-signed per-round deploy funded from
463/// `automation_authority`'s escrow. `selection_mask` must be `Some` for
464/// Discretionary automations and `None` otherwise.
465pub fn get_execute_public_automation_instruction(
466    crank_authority: Pubkey,
467    automation_authority: Pubkey,
468    usd_mint: Pubkey,
469    round_id: u32,
470    selection_mask: Option<u32>,
471) -> Instruction {
472    let board = get_board_address().0;
473    let public_automation = get_public_automation_address(automation_authority).0;
474
475    ExecutePublicAutomation {
476        authority: crank_authority,
477        satrush_config: get_satrush_config_address().0,
478        board,
479        round: get_round_address(round_id).0,
480        public_automation,
481        usd_mint,
482        automation_usd_ata: get_associated_token_address(&public_automation, &usd_mint),
483        board_usd_ata: get_associated_token_address(&board, &usd_mint),
484        public_deployment: get_public_deployment_address(automation_authority, round_id).0,
485        miner: get_miner_address(automation_authority).0,
486        slot_hashes: SLOT_HASHES_ID,
487        token_program: TOKEN_PROGRAM_ID,
488        system_program: SYSTEM_PROGRAM_ID,
489        event_authority: get_event_authority_address().0,
490        program: crate::SATRUSH_ID,
491    }
492    .instruction(ExecutePublicAutomationInstructionArgs { selection_mask })
493}
494
495/// `claim_usd`: withdraw `amount` of the miner `authority`'s unclaimed USD
496/// winnings from the board's USD pool to the authority's USD account. No exit
497/// fee — the full amount transfers.
498pub fn get_claim_usd_instruction(authority: Pubkey, usd_mint: Pubkey, amount: u64) -> Instruction {
499    let board = get_board_address().0;
500    ClaimUsd {
501        authority,
502        satrush_config: get_satrush_config_address().0,
503        board,
504        miner: get_miner_address(authority).0,
505        usd_mint,
506        board_usd_ata: get_associated_token_address(&board, &usd_mint),
507        authority_usd_ata: get_associated_token_address(&authority, &usd_mint),
508        token_program: TOKEN_PROGRAM_ID,
509        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
510        system_program: SYSTEM_PROGRAM_ID,
511    }
512    .instruction(ClaimUsdInstructionArgs { amount })
513}
514
515/// `create_sats_vault`: the sats vault singleton and its BTC reserve pool.
516pub fn get_create_sats_vault_instruction(authority: Pubkey, btc_mint: Pubkey) -> Instruction {
517    let sats_vault = get_sats_vault_address().0;
518    CreateSatsVault {
519        authority,
520        satrush_config: get_satrush_config_address().0,
521        sats_vault,
522        btc_mint,
523        sats_vault_btc_ata: get_associated_token_address(&sats_vault, &btc_mint),
524        token_program: TOKEN_PROGRAM_ID,
525        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
526        system_program: SYSTEM_PROGRAM_ID,
527    }
528    .instruction()
529}
530
531/// `close_round`: tear down a Finished round, sweeping a no-winner round's
532/// orphaned pot (USD and BTC) into the treasury. Signed by the config's admin
533/// authority, which receives the round account's rent.
534pub fn get_close_round_instruction(
535    authority: Pubkey,
536    usd_mint: Pubkey,
537    btc_mint: Pubkey,
538    round_id: u32,
539) -> Instruction {
540    let board = get_board_address().0;
541    let treasury = get_treasury_address().0;
542    CloseRound {
543        authority,
544        satrush_config: get_satrush_config_address().0,
545        board,
546        round: get_round_address(round_id).0,
547        treasury,
548        usd_mint,
549        btc_mint,
550        board_usd_ata: get_associated_token_address(&board, &usd_mint),
551        board_btc_ata: get_associated_token_address(&board, &btc_mint),
552        treasury_usd_ata: get_associated_token_address(&treasury, &usd_mint),
553        treasury_btc_ata: get_associated_token_address(&treasury, &btc_mint),
554        token_program: TOKEN_PROGRAM_ID,
555        associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ID,
556        system_program: SYSTEM_PROGRAM_ID,
557        event_authority: get_event_authority_address().0,
558        program: crate::SATRUSH_ID,
559    }
560    .instruction()
561}