Skip to main content

arcium_client/
instruction.rs

1//! Instruction builders for the Arcium programs.
2use crate::{
3    idl::{
4        arcium::{
5            accounts::MXEAccount,
6            client::{
7                accounts::{
8                    ActivateArx as ActivateArxAccs,
9                    ActivateCluster as ActivateClusterAccs,
10                    BindRecoveryPeerMigration as BindRecoveryPeerMigrationAccs,
11                    BumpEpochCluster as BumpEpochClusterAccs,
12                    CallbackComputation as CallbackComputationAccs,
13                    ClaimComputationRent as ClaimComputationRentAccs,
14                    ClaimFailureAppend as ClaimFailureAppendAccs,
15                    ClaimFailureFinalize as ClaimFailureFinalizeAccs,
16                    ClaimFailureInit as ClaimFailureInitAccs,
17                    ClaimNodeFees as ClaimNodeFeesAccs,
18                    CloseComputationDefinition as CloseComputationDefinitionAccs,
19                    CloseComputationDefinitionBuffers as CloseComputationDefinitionBuffersAccs,
20                    CloseKeyRecovery as CloseKeyRecoveryAccs,
21                    CloseMxe as CloseMxeAccs,
22                    DeactivateArx as DeactivateArxAccs,
23                    DeactivateCluster as DeactivateClusterAccs,
24                    DeactivateComputationDefinition as DeactivateComputationDefinitionAccs,
25                    EmbiggenRawCircuitAcc as EmbiggenRawCircuitAccAccs,
26                    ExtendRecoveryKeyshares as ExtendRecoveryKeysharesAccs,
27                    FinalizeComputationDefinition as FinalizeComputationDefinitionAccs,
28                    FinalizeKeyRecoveryCallback as FinalizeKeyRecoveryCallbackAccs,
29                    FinalizeKeyRecoveryExecution as FinalizeKeyRecoveryExecutionAccs,
30                    FinalizeKeyRecoverySharesUpload as FinalizeKeyRecoverySharesUploadAccs,
31                    FinalizeMxeKeys as FinalizeMxeKeysAccs,
32                    IncreaseMempoolSize as IncreaseMempoolSizeAccs,
33                    Init as InitNetworkProgramAccs,
34                    InitArxNode as InitArxNodeAccs,
35                    InitCluster as InitClusterAccs,
36                    InitComputationDefinition as InitComputationDefinitionAccs,
37                    InitKeyRecoveryExecutionPart1 as InitKeyRecoveryExecutionPart1Accs,
38                    InitKeyRecoveryExecutionPart2 as InitKeyRecoveryExecutionPart2Accs,
39                    InitMxePart1 as InitMxePart1Accs,
40                    InitMxePart2 as InitMxePart2Accs,
41                    InitOperator as InitOperatorAccs,
42                    InitRawCircuitAcc as InitRawCircuitAccs,
43                    InitRecoveryPeerAccount as InitRecoveryPeerAccountAccs,
44                    JoinCluster as JoinClusterAccs,
45                    MigrateArxNode as MigrateArxNodeAccs,
46                    MigrateCluster as MigrateClusterAccs,
47                    MigrateMxeAccount as MigrateMxeAccountAccs,
48                    MigrateRecoveryPeer as MigrateRecoveryPeerAccs,
49                    ProposeFee as ProposeFeeAccs,
50                    ProposeJoinCluster as ProposeJoinClusterAccs,
51                    QueueComputation as QueueComputationAccs,
52                    QueueKeyRecoveryInit as QueueKeyRecoveryInitAccs,
53                    ReclaimExpiredComputationFee as ReclaimExpiredComputationFeeAccs,
54                    ReclaimFailureRentIdempotent as ReclaimFailureRentIdempotentAccs,
55                    RecoverMxe as RecoverMxeAccs,
56                    RegisterAccountInLut as RegisterAccountInLutAccs,
57                    RequeueMxeKeygen as RequeueMxeKeygenAccs,
58                    SetActive as SetActiveAccs,
59                    SetArxNodeConfig as SetArxNodeConfigAccs,
60                    SetArxNodeMetadata as SetArxNodeMetadataAccs,
61                    SetClusterAuthority as SetClusterAuthorityAccs,
62                    SetClusterTdInfo as SetClusterTdInfoAccs,
63                    SetLeaderChoice as SetLeaderChoiceAccs,
64                    SetMxeKeys as SetMxeKeysAccs,
65                    SetMxeRecoveryKeysInit as SetMxeRecoveryKeysInitAccs,
66                    SubmitAggregatedBlsPubkey as SubmitAggregatedBlsPubkeyAccs,
67                    SubmitKeyRecoveryShare as SubmitKeyRecoveryShareAccs,
68                    UpdateCurrentEpochIdempotent as UpdateCurrentEpochIdempotentAccs,
69                    UploadCircuit as UploadCircuitAccs,
70                    VoteFee as VoteFeeAccs,
71                    ZCloseAbortedKeyRecovery as CloseAbortedKeyRecoveryAccs,
72                },
73                args::{
74                    ActivateArx as ActivateArxArgs,
75                    ActivateCluster as ActivateClusterArgs,
76                    BindRecoveryPeerMigration as BindRecoveryPeerMigrationArgs,
77                    BumpEpochCluster as BumpEpochClusterArgs,
78                    CallbackComputation as CallbackComputationArgs,
79                    ClaimComputationRent as ClaimComputationRentArgs,
80                    ClaimFailureAppend as ClaimFailureAppendArgs,
81                    ClaimFailureFinalize as ClaimFailureFinalizeArgs,
82                    ClaimFailureInit as ClaimFailureInitArgs,
83                    ClaimNodeFees as ClaimNodeFeesArgs,
84                    CloseComputationDefinition as CloseComputationDefinitionArgs,
85                    CloseComputationDefinitionBuffers as CloseComputationDefinitionBuffersArgs,
86                    CloseKeyRecovery as CloseKeyRecoveryArgs,
87                    CloseMxe as CloseMxeArgs,
88                    DeactivateArx as DeactivateArxArgs,
89                    DeactivateCluster as DeactivateClusterArgs,
90                    DeactivateComputationDefinition as DeactivateComputationDefinitionArgs,
91                    EmbiggenRawCircuitAcc as EmbiggenRawCircuitAccArgs,
92                    ExtendRecoveryKeyshares as ExtendRecoveryKeysharesArgs,
93                    FinalizeComputationDefinition as FinalizeComputationDefinitionArgs,
94                    FinalizeKeyRecoveryCallback as FinalizeKeyRecoveryCallbackArgs,
95                    FinalizeKeyRecoveryExecution as FinalizeKeyRecoveryExecutionArgs,
96                    FinalizeKeyRecoverySharesUpload as FinalizeKeyRecoverySharesUploadArgs,
97                    FinalizeMxeKeys as FinalizeMxeKeysArgs,
98                    IncreaseMempoolSize as IncreaseMempoolSizeArgs,
99                    Init as InitNetworkProgramArgs,
100                    InitArxNode as InitArxNodeArgs,
101                    InitCluster as InitClusterArgs,
102                    InitComputationDefinition as InitComputationDefinitionArgs,
103                    InitKeyRecoveryExecutionPart1 as InitKeyRecoveryExecutionPart1Args,
104                    InitKeyRecoveryExecutionPart2 as InitKeyRecoveryExecutionPart2Args,
105                    InitMxePart1 as InitMxePart1Args,
106                    InitMxePart2 as InitMxePart2Args,
107                    InitOperator as InitOperatorArgs,
108                    InitRawCircuitAcc as InitRawCircuitArgs,
109                    InitRecoveryPeerAccount as InitRecoveryPeerAccountArgs,
110                    JoinCluster as JoinClusterArgs,
111                    MigrateArxNode as MigrateArxNodeArgs,
112                    MigrateCluster as MigrateClusterArgs,
113                    MigrateMxeAccount as MigrateMxeAccountArgs,
114                    MigrateRecoveryPeer as MigrateRecoveryPeerArgs,
115                    ProposeFee as ProposeFeeArgs,
116                    ProposeJoinCluster as ProposeJoinClusterArgs,
117                    QueueComputation as QueueComputationArgs,
118                    QueueKeyRecoveryInit as QueueKeyRecoveryInitArgs,
119                    ReclaimExpiredComputationFee as ReclaimExpiredComputationFeeArgs,
120                    ReclaimFailureRentIdempotent as ReclaimFailureRentIdempotentArgs,
121                    RecoverMxe as RecoverMxeArgs,
122                    RegisterAccountInLut as RegisterAccountInLutArgs,
123                    RequeueMxeKeygen as RequeueMxeKeygenArgs,
124                    SetActive as SetActiveArgs,
125                    SetArxNodeConfig as SetArxNodeConfigArgs,
126                    SetArxNodeMetadata as SetArxNodeMetadataArgs,
127                    SetClusterAuthority as SetClusterAuthorityArgs,
128                    SetClusterTdInfo as SetClusterTdInfoArgs,
129                    SetLeaderChoice as SetLeaderChoiceArgs,
130                    SetMxeKeys as SetMxeKeysArgs,
131                    SetMxeRecoveryKeysInit as SetMxeRecoveryKeysInitArgs,
132                    SubmitAggregatedBlsPubkey as SubmitAggregatedBlsPubkeyArgs,
133                    SubmitKeyRecoveryShare as SubmitKeyRecoveryShareArgs,
134                    UpdateCurrentEpochIdempotent as UpdateCurrentEpochIdempotentArgs,
135                    UploadCircuit as UploadCircuitArgs,
136                    VoteFee as VoteFeeArgs,
137                    ZCloseAbortedKeyRecovery as CloseAbortedKeyRecoveryArgs,
138                },
139            },
140            types::{
141                ArgumentList,
142                ArxNodeConfig,
143                BN254G2BLSPublicKey,
144                CallbackAccount,
145                CallbackInstruction,
146                CircuitSource,
147                ComputationDefinitionMeta,
148                ComputationSignature,
149                Epoch,
150                ExecutionStatus,
151                LeaderChoice,
152                MempoolSize,
153                NodeMetadata,
154                OperatorMeta,
155                Output,
156                Parameter,
157                Timestamp,
158            },
159            ID as ARCIUM_PROG_ID,
160        },
161        arcium_staking::ID as ARCIUM_STAKING_PROG_ID,
162    },
163    pda::{
164        arx_acc,
165        clock_acc,
166        cluster_acc,
167        computation_acc,
168        computation_definition_acc,
169        execpool_acc,
170        failure_claim_acc,
171        fee_pool_acc,
172        mempool_acc,
173        mxe_acc,
174        mxe_lut_acc,
175        mxe_recovery_acc,
176        operator_acc,
177        permissioned_recovery_peers_acc,
178        raw_circuit_acc,
179        recovery_cluster_acc,
180        recovery_peer_acc,
181        signer_acc,
182        staking::primary_stake_acc,
183    },
184    utils::MAX_RECOVERY_PEERS,
185    MXE_KEYGEN_COMPUTATION_DEFINITION_OFFSET,
186    MXE_KEY_RECOVERY_FINALIZE_COMPUTATION_DEFINITION_OFFSET,
187    MXE_KEY_RECOVERY_INIT_COMPUTATION_DEFINITION_OFFSET,
188};
189use anchor_lang::{prelude::*, solana_program::instruction::Instruction, InstructionData};
190use arcis_compiler::MXE_KEYS_ENC_COUNT;
191use solana_address_lookup_table_interface::program::ID as ADDRESS_LOOKUP_TABLE_PROGRAM_ID;
192use solana_sdk_ids::{
193    system_program::ID as SYSTEM_PROGRAM_ID,
194    sysvar::instructions::ID as INSTRUCTIONS_SYSVAR_ID,
195};
196use std::vec;
197
198pub const ARCIUM_TOKEN_DECIMALS: u8 = 9;
199const RESERVED_MXE_KEYGEN_COMP_DEF_OFFSET: u32 = 1;
200pub const RESERVED_MXE_KEY_RECOVERY_INIT_COMP_DEF_OFFSET: u32 = 2;
201
202/// Migrate a `Cluster` account from a pre-staking layout to the current one. Permissionless and
203/// idempotent; `payer` funds the realloc rent.
204pub fn migrate_cluster_ix(payer: &Pubkey, cluster_offset: u32) -> Instruction {
205    let accounts = MigrateClusterAccs {
206        payer: payer.to_owned(),
207        cluster: cluster_acc(cluster_offset),
208        system_program: SYSTEM_PROGRAM_ID,
209    }
210    .to_account_metas(None);
211    let data = MigrateClusterArgs {}.data();
212    Instruction {
213        program_id: ARCIUM_PROG_ID,
214        accounts,
215        data,
216    }
217}
218
219/// Migrate an `MXEAccount` from a pre-staking layout to the current one. Permissionless and
220/// idempotent; `payer` funds the realloc rent.
221pub fn migrate_mxe_account_ix(payer: &Pubkey, mxe_program: &Pubkey) -> Instruction {
222    let accounts = MigrateMxeAccountAccs {
223        payer: payer.to_owned(),
224        mxe: mxe_acc(mxe_program),
225        system_program: SYSTEM_PROGRAM_ID,
226    }
227    .to_account_metas(None);
228    let data = MigrateMxeAccountArgs {}.data();
229    Instruction {
230        program_id: ARCIUM_PROG_ID,
231        accounts,
232        data,
233    }
234}
235
236/// Migrate a (zero-copy) `RecoveryPeerAccount` from a pre-staking layout to the current one.
237/// Permissionless and idempotent; `payer` funds the realloc rent.
238pub fn migrate_recovery_peer_ix(payer: &Pubkey, peer_offset: u32) -> Instruction {
239    let accounts = MigrateRecoveryPeerAccs {
240        payer: payer.to_owned(),
241        recovery_peer: recovery_peer_acc(peer_offset),
242        system_program: SYSTEM_PROGRAM_ID,
243    }
244    .to_account_metas(None);
245    let data = MigrateRecoveryPeerArgs {}.data();
246    Instruction {
247        program_id: ARCIUM_PROG_ID,
248        accounts,
249        data,
250    }
251}
252
253/// Bind a `PrimaryStakingAccount` to an `ArxNode` created by the pre-staking program (whose
254/// `primary_staking_account` still holds the `ID_CONST` placeholder). The node's `config.authority`
255/// must sign and owns the stake PDA `[PrimaryStakingAccount, authority]`. Bundle in one tx *after*
256/// `add_primary_stake_to_legacy_acc_ix(authority, ..)`.
257pub fn migrate_arx_node_ix(authority: &Pubkey, node_offset: u32) -> Instruction {
258    let accounts = MigrateArxNodeAccs {
259        authority: authority.to_owned(),
260        arx_node_acc: arx_acc(node_offset),
261        primary_stake_account: primary_stake_acc(authority),
262        arcium_staking_program: ARCIUM_STAKING_PROG_ID,
263    }
264    .to_account_metas(None);
265    let data = MigrateArxNodeArgs { node_offset }.data();
266    Instruction {
267        program_id: ARCIUM_PROG_ID,
268        accounts,
269        data,
270    }
271}
272
273/// Bind a `PrimaryStakingAccount` to a layout-migrated `RecoveryPeerAccount`. The peer's
274/// `authority` must sign and owns the stake PDA. Bundle in one tx *after*
275/// `migrate_recovery_peer_ix` (so the field exists) and
276/// `add_primary_stake_to_legacy_acc_ix(authority, ..)`.
277pub fn bind_recovery_peer_migration_ix(authority: &Pubkey, peer_offset: u32) -> Instruction {
278    let accounts = BindRecoveryPeerMigrationAccs {
279        authority: authority.to_owned(),
280        recovery_peer_account: recovery_peer_acc(peer_offset),
281        primary_stake_account: primary_stake_acc(authority),
282        arcium_staking_program: ARCIUM_STAKING_PROG_ID,
283    }
284    .to_account_metas(None);
285    let data = BindRecoveryPeerMigrationArgs { peer_offset }.data();
286    Instruction {
287        program_id: ARCIUM_PROG_ID,
288        accounts,
289        data,
290    }
291}
292
293pub fn init_network_program_ix(current_timestamp: u64, signer: &Pubkey) -> Instruction {
294    let pool_acc = fee_pool_acc();
295    let accounts = InitNetworkProgramAccs {
296        signer: signer.to_owned(),
297        fee_pool: pool_acc,
298        system_program: SYSTEM_PROGRAM_ID,
299        clock: clock_acc(),
300    }
301    .to_account_metas(None);
302    let data = InitNetworkProgramArgs {
303        start_epoch_timestamp: Timestamp {
304            timestamp: current_timestamp,
305        },
306    }
307    .data();
308
309    Instruction {
310        program_id: ARCIUM_PROG_ID,
311        accounts,
312        data,
313    }
314}
315
316// Location as [ISO 3166-1 alpha-2](https://www.iso.org/iso-3166-country-codes.html) country code
317pub fn init_node_operator_acc_ix(signer: &Pubkey, url: String, location: u8) -> Instruction {
318    let accounts = InitOperatorAccs {
319        signer: signer.to_owned(),
320        operator_acc: operator_acc(signer),
321        system_program: SYSTEM_PROGRAM_ID,
322    }
323    .to_account_metas(None);
324    let data = InitOperatorArgs {
325        meta: OperatorMeta { url, location },
326    }
327    .data();
328
329    Instruction {
330        program_id: ARCIUM_PROG_ID,
331        accounts,
332        data,
333    }
334}
335
336#[allow(clippy::too_many_arguments)]
337pub fn init_arx_node_acc_ix(
338    operator_signer: &Pubkey,
339    node_signer: &Pubkey,
340    node_offset: u32,
341    callback_authority: &Pubkey,
342    cu_claim: u64,
343    bls_pubkey: BN254G2BLSPublicKey,
344    bls_pop_sig: [u8; 64],
345    metadata: NodeMetadata,
346    x25519_pubkey: [u8; 32],
347    primary_stake_account: &Pubkey,
348    staker: &Pubkey,
349) -> Instruction {
350    let accounts = InitArxNodeAccs {
351        operator_signer: operator_signer.to_owned(),
352        operator_acc: operator_acc(operator_signer),
353        arx_node_acc: arx_acc(node_offset),
354        primary_stake_account: primary_stake_account.to_owned(),
355        staker: staker.to_owned(),
356        arcium_staking_program: ARCIUM_STAKING_PROG_ID,
357        system_program: SYSTEM_PROGRAM_ID,
358    }
359    .to_account_metas(None);
360    let config = ArxNodeConfig {
361        authority: node_signer.to_owned(),
362        callback_authority: callback_authority.to_owned(),
363    };
364    let data = InitArxNodeArgs {
365        node_offset,
366        cu_capacity_claim: cu_claim,
367        config,
368        bls_pubkey,
369        bls_pop_sig,
370        metadata,
371        x25519_pubkey,
372    }
373    .data();
374
375    Instruction {
376        program_id: ARCIUM_PROG_ID,
377        accounts,
378        data,
379    }
380}
381
382pub fn init_cluster_ix(
383    signer: &Pubkey,
384    cluster_authority: Pubkey,
385    cluster_offset: u32,
386    cluster_size: u16,
387    cu_price: u64,
388    mempool_size: MempoolSize,
389    td_info: Option<NodeMetadata>,
390) -> Instruction {
391    let accounts = InitClusterAccs {
392        signer: signer.to_owned(),
393        cluster_acc: cluster_acc(cluster_offset),
394        authority: cluster_authority,
395        pool_account: fee_pool_acc(),
396        system_program: SYSTEM_PROGRAM_ID,
397        mempool: mempool_acc(cluster_offset),
398        execpool: execpool_acc(cluster_offset),
399        clock: clock_acc(),
400    }
401    .to_account_metas(None);
402    let data = InitClusterArgs {
403        cluster_size,
404        cluster_id: cluster_offset,
405        cu_price,
406        mempool_size,
407        td_info,
408    }
409    .data();
410
411    Instruction {
412        program_id: ARCIUM_PROG_ID,
413        accounts,
414        data,
415    }
416}
417
418pub fn init_recovery_peer_acc_ix(
419    signer: &Pubkey,
420    peer_offset: u32,
421    x25519_pubkey: [u8; 32],
422    primary_stake_account: &Pubkey,
423    staker: &Pubkey,
424) -> Instruction {
425    let accounts = InitRecoveryPeerAccountAccs {
426        signer: signer.to_owned(),
427        recovery_peer_account: recovery_peer_acc(peer_offset),
428        permissioned_recovery_peers_acc: permissioned_recovery_peers_acc(),
429        primary_stake_account: primary_stake_account.to_owned(),
430        staker: staker.to_owned(),
431        arcium_staking_program: ARCIUM_STAKING_PROG_ID,
432        system_program: SYSTEM_PROGRAM_ID,
433    }
434    .to_account_metas(None);
435    let data = InitRecoveryPeerAccountArgs {
436        peer_offset,
437        signer: *signer,
438        x25519_pubkey,
439    }
440    .data();
441
442    Instruction {
443        program_id: ARCIUM_PROG_ID,
444        accounts,
445        data,
446    }
447}
448
449pub fn set_cluster_authority_ix(
450    signer: &Pubkey,
451    cluster_offset: u32,
452    new_authority: Option<Pubkey>,
453) -> Instruction {
454    let accounts = SetClusterAuthorityAccs {
455        current_authority: signer.to_owned(),
456        cluster_acc: cluster_acc(cluster_offset),
457    }
458    .to_account_metas(None);
459    let data = SetClusterAuthorityArgs {
460        cluster_id: cluster_offset,
461        new_authority,
462    }
463    .data();
464
465    Instruction {
466        program_id: ARCIUM_PROG_ID,
467        accounts,
468        data,
469    }
470}
471
472pub fn set_cluster_td_info_ix(
473    signer: &Pubkey,
474    cluster_offset: u32,
475    td_info: Option<NodeMetadata>,
476) -> Instruction {
477    let accounts = SetClusterTdInfoAccs {
478        authority: signer.to_owned(),
479        cluster_acc: cluster_acc(cluster_offset),
480    }
481    .to_account_metas(None);
482    let data = SetClusterTdInfoArgs {
483        cluster_id: cluster_offset,
484        td_info,
485    }
486    .data();
487
488    Instruction {
489        program_id: ARCIUM_PROG_ID,
490        accounts,
491        data,
492    }
493}
494
495pub fn init_mxe_part1_ix(
496    signer: &Pubkey,
497    mxe_program: &Pubkey,
498    recovery_peers: [u32; MAX_RECOVERY_PEERS],
499) -> Instruction {
500    let (program_data, _) =
501        Pubkey::find_program_address(&[mxe_program.as_ref()], &bpf_loader_upgradeable::id());
502
503    let accounts = InitMxePart1Accs {
504        signer: signer.to_owned(),
505        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
506        mxe_program: *mxe_program,
507        program_data,
508        system_program: SYSTEM_PROGRAM_ID,
509    }
510    .to_account_metas(None);
511    let data = InitMxePart1Args { recovery_peers }.data();
512
513    Instruction {
514        program_id: ARCIUM_PROG_ID,
515        accounts,
516        data,
517    }
518}
519
520#[allow(clippy::too_many_arguments)]
521pub fn init_mxe_part2_ix(
522    signer: &Pubkey,
523    mxe_program: &Pubkey,
524    cluster_offset: u32,
525    keygen_offset: u64,
526    key_recovery_init_offset: u64,
527    mxe_authority: Option<Pubkey>,
528    recent_slot: u64,
529) -> Instruction {
530    // Derive program_data PDA for upgrade authority verification
531    let (program_data, _) =
532        Pubkey::find_program_address(&[mxe_program.as_ref()], &bpf_loader_upgradeable::id());
533
534    let accounts = InitMxePart2Accs {
535        signer: signer.to_owned(),
536        address_lookup_table: mxe_lut_acc(mxe_program, recent_slot),
537        cluster: cluster_acc(cluster_offset),
538        mxe: mxe_acc(mxe_program),
539        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
540        executing_pool: execpool_acc(cluster_offset),
541        mempool: mempool_acc(cluster_offset),
542        mxe_keygen_computation_definition: computation_definition_acc(
543            mxe_program,
544            MXE_KEYGEN_COMPUTATION_DEFINITION_OFFSET,
545        ),
546        mxe_keygen_computation: computation_acc(cluster_offset, keygen_offset),
547        key_recovery_init_computation: computation_acc(cluster_offset, key_recovery_init_offset),
548        mxe_authority,
549        mxe_program: *mxe_program,
550        program_data,
551        clock: clock_acc(),
552        pool_account: fee_pool_acc(),
553        instructions_sysvar: INSTRUCTIONS_SYSVAR_ID,
554        system_program: SYSTEM_PROGRAM_ID,
555        lut_program: ADDRESS_LOOKUP_TABLE_PROGRAM_ID,
556    }
557    .to_account_metas(None);
558    let data = InitMxePart2Args {
559        cluster_offset,
560        keygen_offset,
561        key_recovery_init_offset,
562        recent_slot,
563    }
564    .data();
565
566    Instruction {
567        program_id: ARCIUM_PROG_ID,
568        accounts,
569        data,
570    }
571}
572
573pub fn register_account_in_lut_ix(
574    signer: &Pubkey,
575    mxe_program: &Pubkey,
576    lut_slot: u64,
577    account: Pubkey,
578) -> Instruction {
579    let accounts = RegisterAccountInLutAccs {
580        signer: signer.to_owned(),
581        mxe: mxe_acc(mxe_program),
582        mxe_program: *mxe_program,
583        address_lookup_table: mxe_lut_acc(mxe_program, lut_slot),
584        lut_program: ADDRESS_LOOKUP_TABLE_PROGRAM_ID,
585        system_program: SYSTEM_PROGRAM_ID,
586    }
587    .to_account_metas(None);
588
589    let data = RegisterAccountInLutArgs { account }.data();
590
591    Instruction {
592        program_id: ARCIUM_PROG_ID,
593        accounts,
594        data,
595    }
596}
597
598#[allow(clippy::too_many_arguments)]
599pub fn init_computation_definition_ix(
600    signer: &Pubkey,
601    comp_def_offset: u32,
602    mxe_program: &Pubkey,
603    circuit_len: u32,
604    parameters: Vec<Parameter>,
605    outputs: Vec<Output>,
606    cu_amount: u64,
607    circuit_source_override: Option<CircuitSource>,
608    lut_slot: u64,
609) -> Instruction {
610    let comp_def_acc = computation_definition_acc(mxe_program, comp_def_offset);
611
612    let accounts = InitComputationDefinitionAccs {
613        signer: signer.to_owned(),
614        mxe: mxe_acc(mxe_program),
615        address_lookup_table: mxe_lut_acc(mxe_program, lut_slot),
616        comp_def_acc,
617        system_program: SYSTEM_PROGRAM_ID,
618        lut_program: ADDRESS_LOOKUP_TABLE_PROGRAM_ID,
619    }
620    .to_account_metas(None);
621    let data = InitComputationDefinitionArgs {
622        mxe_program: *mxe_program,
623        comp_offset: comp_def_offset,
624        computation_definition: ComputationDefinitionMeta {
625            signature: ComputationSignature {
626                parameters,
627                outputs,
628            },
629            circuit_len,
630        },
631        circuit_source_override,
632        cu_amount,
633    }
634    .data();
635
636    Instruction {
637        program_id: ARCIUM_PROG_ID,
638        accounts,
639        data,
640    }
641}
642
643pub fn init_raw_circuit_acc_ix(
644    signer: &Pubkey,
645    comp_def_offset: u32,
646    mxe_program_id: &Pubkey,
647    circuit_chunk_index: u8,
648) -> Instruction {
649    let comp_def_acc = computation_definition_acc(mxe_program_id, comp_def_offset);
650    let accounts = InitRawCircuitAccs {
651        signer: signer.to_owned(),
652        comp_def_acc,
653        comp_def_raw: raw_circuit_acc(&comp_def_acc, circuit_chunk_index),
654        system_program: SYSTEM_PROGRAM_ID,
655    }
656    .to_account_metas(None);
657    let data = InitRawCircuitArgs {
658        comp_offset: comp_def_offset,
659        mxe_program: mxe_program_id.to_owned(),
660        raw_circuit_index: circuit_chunk_index,
661    }
662    .data();
663
664    Instruction {
665        program_id: ARCIUM_PROG_ID,
666        accounts,
667        data,
668    }
669}
670
671pub fn upload_circuit_ix(
672    signer: &Pubkey,
673    mxe_program_id: &Pubkey,
674    comp_def_offset: u32,
675    circuit_chunk_index: u8,
676    upload_data: [u8; 814],
677    offset: u32,
678) -> Instruction {
679    let comp_def_acc = computation_definition_acc(mxe_program_id, comp_def_offset);
680    let accounts = UploadCircuitAccs {
681        signer: signer.to_owned(),
682        comp_def_raw: raw_circuit_acc(&comp_def_acc, circuit_chunk_index),
683        comp_def_acc,
684        system_program: SYSTEM_PROGRAM_ID,
685    }
686    .to_account_metas(None);
687
688    let data = UploadCircuitArgs {
689        comp_offset: comp_def_offset,
690        mxe_program: mxe_program_id.to_owned(),
691        raw_circuit_index: circuit_chunk_index,
692        upload_data,
693        offset,
694    }
695    .data();
696
697    Instruction {
698        program_id: ARCIUM_PROG_ID,
699        accounts,
700        data,
701    }
702}
703
704pub fn embiggen_raw_circuit_acc_ix(
705    signer: &Pubkey,
706    comp_def_offset: u32,
707    mxe_program_id: &Pubkey,
708    circuit_chunk_index: u8,
709) -> Instruction {
710    let comp_def_acc = computation_definition_acc(mxe_program_id, comp_def_offset);
711
712    let accounts = EmbiggenRawCircuitAccAccs {
713        signer: signer.to_owned(),
714        comp_def_raw: raw_circuit_acc(&comp_def_acc, circuit_chunk_index),
715        comp_def_acc,
716        system_program: SYSTEM_PROGRAM_ID,
717    }
718    .to_account_metas(None);
719
720    let data = EmbiggenRawCircuitAccArgs {
721        comp_offset: comp_def_offset,
722        mxe_program: mxe_program_id.to_owned(),
723        raw_circuit_index: circuit_chunk_index,
724    }
725    .data();
726
727    Instruction {
728        program_id: ARCIUM_PROG_ID,
729        accounts,
730        data,
731    }
732}
733
734pub fn finalize_computation_definition_ix(
735    signer: &Pubkey,
736    comp_def_offset: u32,
737    mxe_program: &Pubkey,
738) -> Instruction {
739    let comp_def_acc = computation_definition_acc(mxe_program, comp_def_offset);
740    let accounts = FinalizeComputationDefinitionAccs {
741        signer: signer.to_owned(),
742        comp_def_acc,
743        comp_def_raw: raw_circuit_acc(&comp_def_acc, 0),
744    }
745    .to_account_metas(None);
746
747    let data = FinalizeComputationDefinitionArgs {
748        comp_offset: comp_def_offset,
749        mxe_program: mxe_program.to_owned(),
750    }
751    .data();
752
753    Instruction {
754        program_id: ARCIUM_PROG_ID,
755        accounts,
756        data,
757    }
758}
759
760pub fn increase_mempool_size_ix(signer: &Pubkey, cluster_offset: u32) -> Instruction {
761    let accounts = IncreaseMempoolSizeAccs {
762        signer: signer.to_owned(),
763        mempool: mempool_acc(cluster_offset),
764        system_program: SYSTEM_PROGRAM_ID,
765    }
766    .to_account_metas(None);
767    let data = IncreaseMempoolSizeArgs { cluster_offset }.data();
768
769    Instruction {
770        program_id: ARCIUM_PROG_ID,
771        accounts,
772        data,
773    }
774}
775
776/// Re-queues the MXE keygen computation if it has expired from the mempool.
777/// This allows retrying the keygen if it wasn't processed in time.
778pub fn requeue_mxe_keygen_ix(
779    signer: &Pubkey,
780    mxe_program: &Pubkey,
781    cluster_offset: u32,
782    computation_offset: u64,
783) -> Instruction {
784    let accounts = RequeueMxeKeygenAccs {
785        signer: signer.to_owned(),
786        mxe: mxe_acc(mxe_program),
787        mempool: mempool_acc(cluster_offset),
788        executing_pool: execpool_acc(cluster_offset),
789        cluster: cluster_acc(cluster_offset),
790        mxe_keygen_computation: computation_acc(cluster_offset, computation_offset),
791        mxe_program: *mxe_program,
792    }
793    .to_account_metas(None);
794    let data = RequeueMxeKeygenArgs { cluster_offset }.data();
795
796    Instruction {
797        program_id: ARCIUM_PROG_ID,
798        accounts,
799        data,
800    }
801}
802
803pub fn queue_key_recovery_init_ix(
804    signer: &Pubkey,
805    mxe_program: &Pubkey,
806    cluster_offset: u32,
807    key_recovery_init_offset: u64,
808) -> Instruction {
809    let accounts = QueueKeyRecoveryInitAccs {
810        signer: signer.to_owned(),
811        mxe: mxe_acc(mxe_program),
812        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
813        executing_pool: execpool_acc(cluster_offset),
814        mempool: mempool_acc(cluster_offset),
815        key_recovery_init_computation_definition: computation_definition_acc(
816            mxe_program,
817            MXE_KEY_RECOVERY_INIT_COMPUTATION_DEFINITION_OFFSET,
818        ),
819        key_recovery_init_computation: computation_acc(cluster_offset, key_recovery_init_offset),
820        mxe_program: *mxe_program,
821        pool_account: fee_pool_acc(),
822        system_program: SYSTEM_PROGRAM_ID,
823    }
824    .to_account_metas(None);
825    let data = QueueKeyRecoveryInitArgs {
826        cluster_offset,
827        mxe_program: *mxe_program,
828    }
829    .data();
830
831    Instruction {
832        program_id: ARCIUM_PROG_ID,
833        accounts,
834        data,
835    }
836}
837
838pub fn propose_join_cluster_ix(
839    cluster_auth_signer: &Pubkey,
840    cluster_offset: u32,
841    node_offset: u32,
842    primary_stake_account: &Pubkey,
843) -> Instruction {
844    let accounts = ProposeJoinClusterAccs {
845        cluster_authority: cluster_auth_signer.to_owned(),
846        cluster_acc: cluster_acc(cluster_offset),
847        arx_node_acc: arx_acc(node_offset),
848        mempool: mempool_acc(cluster_offset),
849        primary_stake_account: primary_stake_account.to_owned(),
850        clock: clock_acc(),
851        system_program: SYSTEM_PROGRAM_ID,
852    }
853    .to_account_metas(None);
854    let data = ProposeJoinClusterArgs {
855        cluster_id: cluster_offset,
856        node_bump: node_offset,
857    }
858    .data();
859
860    Instruction {
861        program_id: ARCIUM_PROG_ID,
862        accounts,
863        data,
864    }
865}
866
867pub fn join_cluster_ix(
868    node_auth_signer: &Pubkey,
869    cluster_offset: u32,
870    node_offset: u32,
871    join: bool,
872) -> Instruction {
873    let accounts = JoinClusterAccs {
874        node_authority: node_auth_signer.to_owned(),
875        cluster_acc: cluster_acc(cluster_offset),
876        arx_node_acc: arx_acc(node_offset),
877        clock: clock_acc(),
878        system_program: SYSTEM_PROGRAM_ID,
879    }
880    .to_account_metas(None);
881    let data = JoinClusterArgs {
882        cluster_id: cluster_offset,
883        node_bump: node_offset,
884        join,
885    }
886    .data();
887
888    Instruction {
889        program_id: ARCIUM_PROG_ID,
890        accounts,
891        data,
892    }
893}
894
895#[allow(clippy::too_many_arguments)]
896pub fn queue_computation_ix(
897    payer: &Pubkey,
898    mxe_program: &Pubkey,
899    computation_offset: u64,
900    comp_def_offset: u32,
901    args: ArgumentList,
902    cu_price_micro: u64,
903    callback_cu_limit: u32,
904    mxe_account: MXEAccount,
905    callback_instructions: Vec<CallbackInstruction>,
906    callback_transaction_count_required: u8,
907) -> Result<Instruction> {
908    let accounts = QueueComputationAccs {
909        signer: payer.to_owned(),
910        sign_seed: signer_acc(mxe_program),
911        cluster: cluster_acc(mxe_account.cluster),
912        mxe: mxe_acc(mxe_program),
913        mempool: mempool_acc(mxe_account.cluster),
914        executing_pool: execpool_acc(mxe_account.cluster),
915        comp_def_acc: computation_definition_acc(mxe_program, comp_def_offset),
916        pool_account: fee_pool_acc(),
917        system_program: SYSTEM_PROGRAM_ID,
918        clock: clock_acc(),
919        comp: computation_acc(mxe_account.cluster, computation_offset),
920    }
921    .to_account_metas(None);
922    let data = QueueComputationArgs {
923        mxe_program: *mxe_program,
924        comp_offset: computation_offset,
925        computation_definition_offset: comp_def_offset,
926        callback_cu_limit,
927        padding: 0,
928        cu_price_micro,
929        args,
930        custom_callback_instructions: callback_instructions,
931        callback_transactions_required: callback_transaction_count_required,
932    }
933    .data();
934
935    Ok(Instruction {
936        program_id: ARCIUM_PROG_ID,
937        accounts,
938        data,
939    })
940}
941
942pub fn propose_fee_ix(
943    node_auth_signer: Pubkey,
944    cluster_offset: u32,
945    node_offset: u32,
946    proposed_fee: u64,
947) -> Instruction {
948    let accounts = ProposeFeeAccs {
949        node_authority: node_auth_signer,
950        cluster_acc: cluster_acc(cluster_offset),
951        arx_node_acc: arx_acc(node_offset),
952        clock: clock_acc(),
953    }
954    .to_account_metas(None);
955    let data = ProposeFeeArgs {
956        cluster_offset,
957        node_offset,
958        proposed_fee,
959    }
960    .data();
961
962    Instruction {
963        program_id: ARCIUM_PROG_ID,
964        accounts,
965        data,
966    }
967}
968
969pub fn vote_fee_ix(
970    node_auth_signer: Pubkey,
971    cluster_offset: u32,
972    node_offset: u32,
973    fee_vote: u64,
974) -> Instruction {
975    let accounts = VoteFeeAccs {
976        node_authority: node_auth_signer,
977        cluster_acc: cluster_acc(cluster_offset),
978        arx_node_acc: arx_acc(node_offset),
979        clock: clock_acc(),
980    }
981    .to_account_metas(None);
982    let data = VoteFeeArgs {
983        cluster_offset,
984        node_offset,
985        fee_vote,
986    }
987    .data();
988
989    Instruction {
990        program_id: ARCIUM_PROG_ID,
991        accounts,
992        data,
993    }
994}
995
996pub fn set_leader_choice_ix(
997    node_auth_signer: Pubkey,
998    cluster_offset: u32,
999    node_offset: u32,
1000    choice: LeaderChoice,
1001) -> Instruction {
1002    let accounts = SetLeaderChoiceAccs {
1003        node_authority: node_auth_signer,
1004        cluster_acc: cluster_acc(cluster_offset),
1005        arx_node_acc: arx_acc(node_offset),
1006        mempool: mempool_acc(cluster_offset),
1007    }
1008    .to_account_metas(None);
1009    let data = SetLeaderChoiceArgs {
1010        cluster_offset,
1011        node_offset,
1012        choice,
1013    }
1014    .data();
1015
1016    Instruction {
1017        program_id: ARCIUM_PROG_ID,
1018        accounts,
1019        data,
1020    }
1021}
1022
1023/// Builds a `claim_node_fees` instruction. This instruction is **CPI-only** — it must be invoked
1024/// from the `arcium_staking` program with the staking pool PDA as signer. This helper is kept
1025/// for completeness (IDL roundtrip, integration tests driven via CPI) but a raw client cannot
1026/// sign for the PDA, so invoking this directly from outside `arcium_staking` will fail.
1027pub fn claim_node_fees_ix(
1028    staking_pool_signer: &Pubkey,
1029    primary_stake_account: &Pubkey,
1030    cluster_offset: u32,
1031    node_offset: u32,
1032) -> Instruction {
1033    let accounts = ClaimNodeFeesAccs {
1034        staking_pool_signer: *staking_pool_signer,
1035        primary_stake_account: *primary_stake_account,
1036        cluster: cluster_acc(cluster_offset),
1037        node: arx_acc(node_offset),
1038        pool: fee_pool_acc(),
1039    }
1040    .to_account_metas(None);
1041
1042    let data = ClaimNodeFeesArgs {
1043        cluster_offset,
1044        node_offset,
1045    }
1046    .data();
1047
1048    Instruction {
1049        program_id: ARCIUM_PROG_ID,
1050        accounts,
1051        data,
1052    }
1053}
1054
1055pub fn bump_epoch_cluster_ix(cluster_offset: u32) -> Instruction {
1056    let accounts = BumpEpochClusterAccs {
1057        cluster_acc: cluster_acc(cluster_offset),
1058        clock: clock_acc(),
1059    }
1060    .to_account_metas(None);
1061    let data = BumpEpochClusterArgs { cluster_offset }.data();
1062
1063    Instruction {
1064        program_id: ARCIUM_PROG_ID,
1065        accounts,
1066        data,
1067    }
1068}
1069
1070pub fn activate_arx_ix(signer: &Pubkey, node_offset: u32) -> Instruction {
1071    let arx_node_acc = arx_acc(node_offset);
1072    let accounts = ActivateArxAccs {
1073        signer: signer.key(),
1074        arx_node_acc,
1075    }
1076    .to_account_metas(None);
1077    let data = ActivateArxArgs { node_offset }.data();
1078
1079    Instruction {
1080        program_id: ARCIUM_PROG_ID,
1081        accounts,
1082        data,
1083    }
1084}
1085
1086pub fn deactivate_arx_ix(
1087    signer: &Pubkey,
1088    node_offset: u32,
1089    cluster_offset: Option<u32>,
1090) -> Instruction {
1091    let cluster_acc = cluster_offset.map(cluster_acc);
1092
1093    let arx_node_acc = arx_acc(node_offset);
1094    let accounts = DeactivateArxAccs {
1095        signer: signer.key(),
1096        arx_node_acc,
1097        clock: clock_acc(),
1098        cluster_acc,
1099    }
1100    .to_account_metas(None);
1101    let data = DeactivateArxArgs { node_offset }.data();
1102
1103    Instruction {
1104        program_id: ARCIUM_PROG_ID,
1105        accounts,
1106        data,
1107    }
1108}
1109
1110pub fn activate_cluster_ix(signer: &Pubkey, cluster_offset: u32) -> Instruction {
1111    let accounts = ActivateClusterAccs {
1112        authority: signer.key(),
1113        cluster_acc: cluster_acc(cluster_offset),
1114        clock: clock_acc(),
1115    }
1116    .to_account_metas(None);
1117    let data = ActivateClusterArgs {
1118        cluster_id: cluster_offset,
1119    }
1120    .data();
1121
1122    Instruction {
1123        program_id: ARCIUM_PROG_ID,
1124        accounts,
1125        data,
1126    }
1127}
1128
1129pub fn deactivate_cluster_ix(
1130    signer: &Pubkey,
1131    cluster_offset: u32,
1132    deactivation_epoch: Epoch,
1133) -> Instruction {
1134    let accounts = DeactivateClusterAccs {
1135        authority: signer.key(),
1136        cluster_acc: cluster_acc(cluster_offset),
1137        clock: clock_acc(),
1138    }
1139    .to_account_metas(None);
1140    let data = DeactivateClusterArgs {
1141        cluster_id: cluster_offset,
1142        deactivation_epoch,
1143    }
1144    .data();
1145
1146    Instruction {
1147        program_id: ARCIUM_PROG_ID,
1148        accounts,
1149        data,
1150    }
1151}
1152
1153#[allow(clippy::too_many_arguments)]
1154pub fn set_mxe_keys_ix(
1155    signer: &Pubkey,
1156    mxe_program: &Pubkey,
1157    node_offset: u32,
1158    cluster_offset: u32,
1159    mxe_x25519_pubkey: [u8; 32],
1160    mxe_ed25519_verifying_key: [u8; 32],
1161    mxe_elgamal_pubkey: [u8; 32],
1162    mxe_pubkey_validity_proof: [u8; 64],
1163) -> Instruction {
1164    let accounts = SetMxeKeysAccs {
1165        signer: signer.key(),
1166        node: arx_acc(node_offset),
1167        mxe: mxe_acc(mxe_program),
1168        cluster_acc: cluster_acc(cluster_offset),
1169    }
1170    .to_account_metas(None);
1171    let data = SetMxeKeysArgs {
1172        node_offset,
1173        _mxe_program: *mxe_program,
1174        mxe_x25519_pubkey,
1175        mxe_ed25519_verifying_key,
1176        mxe_elgamal_pubkey,
1177        mxe_pubkey_validity_proof,
1178    }
1179    .data();
1180
1181    Instruction {
1182        program_id: ARCIUM_PROG_ID,
1183        accounts,
1184        data,
1185    }
1186}
1187
1188pub fn finalize_mxe_keys_ix(
1189    signer: &Pubkey,
1190    mxe_program: &Pubkey,
1191    cluster_offset: u32,
1192) -> Instruction {
1193    let accounts = FinalizeMxeKeysAccs {
1194        signer: signer.key(),
1195        mxe: mxe_acc(mxe_program),
1196        cluster: cluster_acc(cluster_offset),
1197        system_program: SYSTEM_PROGRAM_ID,
1198    }
1199    .to_account_metas(None);
1200    let data = FinalizeMxeKeysArgs {
1201        _mxe_program: *mxe_program,
1202    }
1203    .data();
1204
1205    Instruction {
1206        program_id: ARCIUM_PROG_ID,
1207        accounts,
1208        data,
1209    }
1210}
1211
1212#[allow(clippy::too_many_arguments)]
1213pub fn set_mxe_recovery_keys_init_ix(
1214    signer: &Pubkey,
1215    mxe_program: &Pubkey,
1216    node_offset: u32,
1217    cluster_offset: u32,
1218    nonce: u128,
1219    encrypted_mxe_keys: [[u8; 32]; MXE_KEYS_ENC_COUNT],
1220    key_material_hash: [u8; 32],
1221    bls_sig: [u8; 64],
1222) -> Instruction {
1223    let accounts = SetMxeRecoveryKeysInitAccs {
1224        signer: signer.key(),
1225        node: arx_acc(node_offset),
1226        mxe: mxe_acc(mxe_program),
1227        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
1228        cluster_acc: cluster_acc(cluster_offset),
1229    }
1230    .to_account_metas(None);
1231    let data = SetMxeRecoveryKeysInitArgs {
1232        node_offset,
1233        _mxe_program: *mxe_program,
1234        nonce: nonce.to_le_bytes(),
1235        encrypted_mxe_keys,
1236        key_material_hash,
1237        bls_sig,
1238    }
1239    .data();
1240
1241    Instruction {
1242        program_id: ARCIUM_PROG_ID,
1243        accounts,
1244        data,
1245    }
1246}
1247
1248pub fn extend_recovery_keyshares_ix(
1249    signer: &Pubkey,
1250    mxe_program: &Pubkey,
1251    node_offset: u32,
1252    cluster_offset: u32,
1253    keyshares_offset: u32,
1254    keyshares: Vec<[[u8; 32]; 5]>,
1255) -> Instruction {
1256    let accounts = ExtendRecoveryKeysharesAccs {
1257        signer: signer.key(),
1258        node: arx_acc(node_offset),
1259        mxe: mxe_acc(mxe_program),
1260        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
1261        cluster_acc: cluster_acc(cluster_offset),
1262    }
1263    .to_account_metas(None);
1264    let data = ExtendRecoveryKeysharesArgs {
1265        node_offset,
1266        _mxe_program: *mxe_program,
1267        keyshares_offset,
1268        keyshares,
1269    }
1270    .data();
1271
1272    Instruction {
1273        program_id: ARCIUM_PROG_ID,
1274        accounts,
1275        data,
1276    }
1277}
1278
1279pub fn finalize_key_recovery_shares_upload_ix(
1280    signer: &Pubkey,
1281    mxe_program: &Pubkey,
1282    node_offset: u32,
1283    cluster_offset: u32,
1284    computation_offset: u64,
1285) -> Instruction {
1286    let accounts = FinalizeKeyRecoverySharesUploadAccs {
1287        signer: signer.key(),
1288        node: arx_acc(node_offset),
1289        mxe: mxe_acc(mxe_program),
1290        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
1291        cluster_acc: cluster_acc(cluster_offset),
1292        comp: computation_acc(cluster_offset, computation_offset),
1293    }
1294    .to_account_metas(None);
1295    let data = FinalizeKeyRecoverySharesUploadArgs {
1296        node_offset,
1297        _mxe_program: *mxe_program,
1298        computation_offset,
1299    }
1300    .data();
1301
1302    Instruction {
1303        program_id: ARCIUM_PROG_ID,
1304        accounts,
1305        data,
1306    }
1307}
1308
1309// =============================================================================
1310// KEY RECOVERY EXECUTION INSTRUCTION BUILDERS
1311// =============================================================================
1312
1313/// Sets an MXE to the `Migration` state, enabling the recovery process to begin.
1314pub fn set_migration_ix(authority: &Pubkey, mxe_program: &Pubkey) -> Instruction {
1315    let accounts = RecoverMxeAccs {
1316        authority: authority.key(),
1317        mxe: mxe_acc(mxe_program),
1318        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
1319        mxe_program: *mxe_program,
1320    }
1321    .to_account_metas(None);
1322    let data = RecoverMxeArgs {
1323        mxe_program: *mxe_program,
1324    }
1325    .data();
1326
1327    Instruction {
1328        program_id: ARCIUM_PROG_ID,
1329        accounts,
1330        data,
1331    }
1332}
1333
1334/// Sets an MXE to `Active`.
1335pub fn set_active_ix(signer: &Pubkey, mxe_program: &Pubkey) -> Instruction {
1336    let accounts = SetActiveAccs {
1337        signer: signer.key(),
1338        mxe: mxe_acc(mxe_program),
1339        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
1340        mxe_recovery_account: mxe_recovery_acc(mxe_program),
1341        mxe_program: *mxe_program,
1342    }
1343    .to_account_metas(None);
1344    let data = SetActiveArgs {
1345        mxe_program: *mxe_program,
1346    }
1347    .data();
1348
1349    Instruction {
1350        program_id: ARCIUM_PROG_ID,
1351        accounts,
1352        data,
1353    }
1354}
1355
1356/// Part 1 of key recovery execution initialization.
1357/// Creates the MxeRecoveryAccount with partial size due to Solana's 10KB limit.
1358/// Authority is used to verify ownership, payer pays for the account.
1359pub fn init_key_recovery_execution_part1_ix(
1360    authority: &Pubkey,
1361    payer: &Pubkey,
1362    original_mxe_program: &Pubkey,
1363    backup_mxe_program: &Pubkey,
1364) -> Instruction {
1365    let accounts = InitKeyRecoveryExecutionPart1Accs {
1366        authority: authority.key(),
1367        payer: payer.key(),
1368        original_mxe: mxe_acc(original_mxe_program),
1369        mxe_recovery_account: mxe_recovery_acc(original_mxe_program),
1370        original_mxe_program: *original_mxe_program,
1371        backup_mxe_program: *backup_mxe_program,
1372        system_program: SYSTEM_PROGRAM_ID,
1373    }
1374    .to_account_metas(None);
1375    let data = InitKeyRecoveryExecutionPart1Args {
1376        original_mxe_program: *original_mxe_program,
1377        backup_mxe_program: *backup_mxe_program,
1378    }
1379    .data();
1380
1381    Instruction {
1382        program_id: ARCIUM_PROG_ID,
1383        accounts,
1384        data,
1385    }
1386}
1387
1388/// Part 2 of key recovery execution initialization.
1389/// Finishes allocating MxeRecoveryAccount and creates the computation definition.
1390/// Payer is used for both authority and payer accounts.
1391pub fn init_key_recovery_execution_part2_ix(
1392    payer: &Pubkey,
1393    original_mxe_program: &Pubkey,
1394    backup_mxe_program: &Pubkey,
1395    cluster_offset: u32,
1396    key_recovery_finalize_offset: u64,
1397) -> Instruction {
1398    let accounts = InitKeyRecoveryExecutionPart2Accs {
1399        authority: payer.key(),
1400        payer: payer.key(),
1401        original_mxe: mxe_acc(original_mxe_program),
1402        backup_mxe: mxe_acc(backup_mxe_program),
1403        recovery_cluster_acc: recovery_cluster_acc(original_mxe_program),
1404        mxe_recovery_account: mxe_recovery_acc(original_mxe_program),
1405        key_recovery_finalize_comp_def: computation_definition_acc(
1406            backup_mxe_program,
1407            MXE_KEY_RECOVERY_FINALIZE_COMPUTATION_DEFINITION_OFFSET,
1408        ),
1409        key_recovery_finalize_computation: computation_acc(
1410            cluster_offset,
1411            key_recovery_finalize_offset,
1412        ),
1413        original_mxe_program: *original_mxe_program,
1414        backup_mxe_program: *backup_mxe_program,
1415        system_program: SYSTEM_PROGRAM_ID,
1416    }
1417    .to_account_metas(None);
1418    let data = InitKeyRecoveryExecutionPart2Args {
1419        original_mxe_program: *original_mxe_program,
1420        backup_mxe_program: *backup_mxe_program,
1421        cluster_offset,
1422        key_recovery_finalize_offset,
1423    }
1424    .data();
1425
1426    Instruction {
1427        program_id: ARCIUM_PROG_ID,
1428        accounts,
1429        data,
1430    }
1431}
1432
1433/// Submits a recovery share from a recovery peer.
1434/// Each share contains RESCUE_KEY_COUNT (5) field elements of 32 bytes each.
1435#[allow(clippy::type_complexity)]
1436pub fn submit_key_recovery_share_ix(
1437    signer: &Pubkey,
1438    original_mxe_program: &Pubkey,
1439    backup_mxe_program: &Pubkey,
1440    peer_offset: u32,
1441    peer_index: u32,
1442    share: [[u8; 32]; 5],
1443) -> Instruction {
1444    let accounts = SubmitKeyRecoveryShareAccs {
1445        signer: signer.key(),
1446        recovery_peer_account: recovery_peer_acc(peer_offset),
1447        original_mxe: mxe_acc(original_mxe_program),
1448        recovery_cluster_acc: recovery_cluster_acc(original_mxe_program),
1449        mxe_recovery_account: mxe_recovery_acc(original_mxe_program),
1450        original_mxe_program: *original_mxe_program,
1451        backup_mxe_program: *backup_mxe_program,
1452    }
1453    .to_account_metas(None);
1454    let data = SubmitKeyRecoveryShareArgs {
1455        original_mxe_program: *original_mxe_program,
1456        backup_mxe_program: *backup_mxe_program,
1457        peer_offset,
1458        peer_index,
1459        share,
1460    }
1461    .data();
1462
1463    Instruction {
1464        program_id: ARCIUM_PROG_ID,
1465        accounts,
1466        data,
1467    }
1468}
1469
1470/// Queues the key_recovery_finalize computation after threshold is met.
1471#[allow(clippy::too_many_arguments)]
1472pub fn queue_key_recovery_finalize_ix(
1473    authority: &Pubkey,
1474    payer: &Pubkey,
1475    original_mxe_program: &Pubkey,
1476    backup_mxe_program: &Pubkey,
1477    cluster_offset: u32,
1478    key_recovery_finalize_offset: u64,
1479    lut_slot: u64,
1480) -> Instruction {
1481    let accounts = FinalizeKeyRecoveryExecutionAccs {
1482        authority: authority.key(),
1483        payer: payer.key(),
1484        original_mxe: mxe_acc(original_mxe_program),
1485        backup_mxe: mxe_acc(backup_mxe_program),
1486        recovery_cluster_acc: recovery_cluster_acc(original_mxe_program),
1487        mxe_recovery_account: mxe_recovery_acc(original_mxe_program),
1488        key_recovery_finalize_comp_def: computation_definition_acc(
1489            backup_mxe_program,
1490            MXE_KEY_RECOVERY_FINALIZE_COMPUTATION_DEFINITION_OFFSET,
1491        ),
1492        key_recovery_finalize_computation: computation_acc(
1493            cluster_offset,
1494            key_recovery_finalize_offset,
1495        ),
1496        executing_pool: execpool_acc(cluster_offset),
1497        mempool: mempool_acc(cluster_offset),
1498        pool_account: fee_pool_acc(),
1499        original_mxe_program: *original_mxe_program,
1500        backup_mxe_program: *backup_mxe_program,
1501        system_program: SYSTEM_PROGRAM_ID,
1502        address_lookup_table: mxe_lut_acc(original_mxe_program, lut_slot),
1503        cluster_acc: cluster_acc(cluster_offset),
1504        lut_program: ADDRESS_LOOKUP_TABLE_PROGRAM_ID,
1505    }
1506    .to_account_metas(None);
1507    let data = FinalizeKeyRecoveryExecutionArgs {
1508        original_mxe_program: *original_mxe_program,
1509        backup_mxe_program: *backup_mxe_program,
1510        cluster_offset,
1511    }
1512    .data();
1513
1514    Instruction {
1515        program_id: ARCIUM_PROG_ID,
1516        accounts,
1517        data,
1518    }
1519}
1520
1521/// Closes recovery-related accounts in the success path (replaces cancel_key_recovery_execution).
1522pub fn close_successful_key_recovery_ix(
1523    authority: &Pubkey,
1524    original_mxe_program: &Pubkey,
1525    backup_mxe_program: &Pubkey,
1526    backup_cluster_offset: u32,
1527    key_recovery_finalize_offset: u64,
1528) -> Instruction {
1529    let accounts = CloseKeyRecoveryAccs {
1530        authority: authority.key(),
1531        original_mxe: mxe_acc(original_mxe_program),
1532        backup_mxe: mxe_acc(backup_mxe_program),
1533        mxe_recovery_account: mxe_recovery_acc(original_mxe_program),
1534        key_recovery_finalize_comp_def: computation_definition_acc(
1535            backup_mxe_program,
1536            MXE_KEY_RECOVERY_FINALIZE_COMPUTATION_DEFINITION_OFFSET,
1537        ),
1538        key_recovery_finalize_computation: computation_acc(
1539            backup_cluster_offset,
1540            key_recovery_finalize_offset,
1541        ),
1542        original_mxe_program: *original_mxe_program,
1543        backup_mxe_program: *backup_mxe_program,
1544    }
1545    .to_account_metas(None);
1546    let data = CloseKeyRecoveryArgs {
1547        original_mxe_program: *original_mxe_program,
1548        backup_cluster_offset,
1549    }
1550    .data();
1551
1552    Instruction {
1553        program_id: ARCIUM_PROG_ID,
1554        accounts,
1555        data,
1556    }
1557}
1558
1559/// Closes recovery-related accounts in the cancel path.
1560pub fn close_aborted_key_recovery_ix(
1561    authority: &Pubkey,
1562    original_mxe_program: &Pubkey,
1563    backup_mxe_program: &Pubkey,
1564    backup_cluster_offset: u32,
1565    key_recovery_finalize_offset: u64,
1566) -> Instruction {
1567    let accounts = CloseAbortedKeyRecoveryAccs {
1568        authority: authority.key(),
1569        original_mxe: mxe_acc(original_mxe_program),
1570        backup_mxe: mxe_acc(backup_mxe_program),
1571        mxe_recovery_account: mxe_recovery_acc(original_mxe_program),
1572        key_recovery_finalize_comp_def: computation_definition_acc(
1573            backup_mxe_program,
1574            MXE_KEY_RECOVERY_FINALIZE_COMPUTATION_DEFINITION_OFFSET,
1575        ),
1576        key_recovery_finalize_computation: computation_acc(
1577            backup_cluster_offset,
1578            key_recovery_finalize_offset,
1579        ),
1580        executing_pool: execpool_acc(backup_cluster_offset),
1581        original_mxe_program: *original_mxe_program,
1582        backup_mxe_program: *backup_mxe_program,
1583    }
1584    .to_account_metas(None);
1585    let data = CloseAbortedKeyRecoveryArgs {
1586        original_mxe_program: *original_mxe_program,
1587        backup_cluster_offset,
1588    }
1589    .data();
1590
1591    Instruction {
1592        program_id: ARCIUM_PROG_ID,
1593        accounts,
1594        data,
1595    }
1596}
1597
1598/// Callback for the key_recovery_finalize computation.
1599#[allow(clippy::too_many_arguments)]
1600pub fn finalize_key_recovery_callback_ix(
1601    signer: &Pubkey,
1602    original_mxe_program: &Pubkey,
1603    backup_mxe_program: &Pubkey,
1604    cluster_offset: u32,
1605    comp_offset: u64,
1606    node_offset: u32,
1607    execution_status: ExecutionStatus,
1608    callback_transaction_index: u8,
1609    output_bytes: Vec<u8>,
1610    bls_sig: [u8; 64],
1611) -> Instruction {
1612    let accounts = FinalizeKeyRecoveryCallbackAccs {
1613        signer: signer.key(),
1614        original_mxe: mxe_acc(original_mxe_program),
1615        backup_mxe: mxe_acc(backup_mxe_program),
1616        mxe_recovery_account: mxe_recovery_acc(original_mxe_program),
1617        computation: computation_acc(cluster_offset, comp_offset),
1618        comp_def: computation_definition_acc(
1619            backup_mxe_program,
1620            MXE_KEY_RECOVERY_FINALIZE_COMPUTATION_DEFINITION_OFFSET,
1621        ),
1622        node: arx_acc(node_offset),
1623        cluster_acc: cluster_acc(cluster_offset),
1624        executing_pool: execpool_acc(cluster_offset),
1625        mempool: mempool_acc(cluster_offset),
1626        original_mxe_program: *original_mxe_program,
1627        backup_mxe_program: *backup_mxe_program,
1628    }
1629    .to_account_metas(None);
1630    let data = FinalizeKeyRecoveryCallbackArgs {
1631        original_mxe_program: *original_mxe_program,
1632        backup_mxe_program: *backup_mxe_program,
1633        cluster_offset,
1634        comp_offset,
1635        node_offset,
1636        execution_status,
1637        callback_transaction_index,
1638        output_bytes,
1639        bls_sig,
1640    }
1641    .data();
1642
1643    Instruction {
1644        program_id: ARCIUM_PROG_ID,
1645        accounts,
1646        data,
1647    }
1648}
1649
1650pub fn claim_computation_rent_ix(
1651    signer: &Pubkey,
1652    computation_offset: u64,
1653    cluster_offset: u32,
1654) -> Instruction {
1655    let accounts = ClaimComputationRentAccs {
1656        signer: signer.key(),
1657        comp: computation_acc(cluster_offset, computation_offset),
1658        system_program: SYSTEM_PROGRAM_ID,
1659    }
1660    .to_account_metas(None);
1661    let data = ClaimComputationRentArgs {
1662        comp_offset: computation_offset,
1663        cluster_offset,
1664    }
1665    .data();
1666
1667    Instruction {
1668        program_id: ARCIUM_PROG_ID,
1669        accounts,
1670        data,
1671    }
1672}
1673
1674#[allow(clippy::too_many_arguments)]
1675pub fn callback_computation_ix(
1676    signer: &Pubkey,
1677    mxe_program: &Pubkey,
1678    computation_offset: u64,
1679    comp_def_offset: u32,
1680    node_offset: u32,
1681    cluster_offset: u32,
1682    execution_status: ExecutionStatus,
1683    callback_transaction_index: u8,
1684) -> Instruction {
1685    let accounts = CallbackComputationAccs {
1686        signer: signer.key(),
1687        node: arx_acc(node_offset),
1688        comp: computation_acc(cluster_offset, computation_offset),
1689        mxe: mxe_acc(mxe_program),
1690        cluster_acc: cluster_acc(cluster_offset),
1691        mempool: mempool_acc(cluster_offset),
1692        executing_pool: execpool_acc(cluster_offset),
1693        comp_def_acc: computation_definition_acc(mxe_program, comp_def_offset),
1694        instructions_sysvar: INSTRUCTIONS_SYSVAR_ID,
1695    }
1696    .to_account_metas(None);
1697    let data = CallbackComputationArgs {
1698        node_offset,
1699        comp_def_offset,
1700        comp_offset: computation_offset,
1701        mxe_program: *mxe_program,
1702        execution_status,
1703        callback_transaction_index,
1704    }
1705    .data();
1706
1707    Instruction {
1708        program_id: ARCIUM_PROG_ID,
1709        accounts,
1710        data,
1711    }
1712}
1713
1714// Callback computation instruction on the user program.
1715pub fn callback_computation_ix_user(
1716    mxe_prog_id: &Pubkey,
1717    callback_accs: Vec<CallbackAccount>,
1718    comp_def_offset: u32,
1719    callback_discriminator: &[u8],
1720    output_bytes: Vec<u8>,
1721) -> Instruction {
1722    let mut bytes = Vec::with_capacity(callback_discriminator.len() + output_bytes.len());
1723    bytes.extend_from_slice(callback_discriminator);
1724    bytes.extend_from_slice(&output_bytes);
1725
1726    let accounts = vec![
1727        // `arcium_program`
1728        AccountMeta {
1729            pubkey: ARCIUM_PROG_ID,
1730            is_signer: false,
1731            is_writable: false,
1732        },
1733        // `computation_definition_account`
1734        AccountMeta {
1735            pubkey: computation_definition_acc(mxe_prog_id, comp_def_offset),
1736            is_signer: false,
1737            is_writable: false,
1738        },
1739        // `instructions_sysvar` Needed for acc introspection
1740        AccountMeta {
1741            pubkey: INSTRUCTIONS_SYSVAR_ID,
1742            is_signer: false,
1743            is_writable: false,
1744        },
1745    ]
1746    .into_iter()
1747    .chain(callback_accs.iter().map(|c| AccountMeta {
1748        pubkey: c.pubkey,
1749        is_writable: c.is_writable,
1750        is_signer: false,
1751    }))
1752    .collect::<Vec<AccountMeta>>()
1753    .to_account_metas(None);
1754
1755    Instruction {
1756        program_id: mxe_prog_id.to_owned(),
1757        accounts,
1758        data: bytes,
1759    }
1760}
1761
1762pub fn claim_failure_init_ix(
1763    signer: &Pubkey,
1764    mxe_program_id: &Pubkey,
1765    cluster_offset: u32,
1766    comp_def_offset: u32,
1767    computation_offset: u64,
1768    node_offset: u32,
1769    output_len_bytes: u32,
1770) -> Instruction {
1771    let accounts = ClaimFailureInitAccs {
1772        signer: signer.key(),
1773        node_acc: arx_acc(node_offset),
1774        mxe: mxe_acc(mxe_program_id),
1775        cluster_acc: cluster_acc(cluster_offset),
1776        comp_acc: computation_acc(cluster_offset, computation_offset),
1777        comp_def_acc: computation_definition_acc(mxe_program_id, comp_def_offset),
1778        failure_acc: failure_claim_acc(mxe_program_id, computation_offset),
1779        system_program: SYSTEM_PROGRAM_ID,
1780    }
1781    .to_account_metas(None);
1782    let data = ClaimFailureInitArgs {
1783        comp_offset: computation_offset,
1784        node_offset,
1785        mxe_program: mxe_program_id.to_owned(),
1786        output_len_bytes,
1787    }
1788    .data();
1789
1790    Instruction {
1791        program_id: ARCIUM_PROG_ID,
1792        accounts,
1793        data,
1794    }
1795}
1796
1797pub fn claim_failure_append_ix(
1798    signer: &Pubkey,
1799    mxe_program_id: &Pubkey,
1800    computation_offset: u64,
1801    chunk: Vec<u8>,
1802    failure_claim_offset: u32,
1803) -> Instruction {
1804    let accounts = ClaimFailureAppendAccs {
1805        signer: signer.key(),
1806        failure_acc: failure_claim_acc(mxe_program_id, computation_offset),
1807    }
1808    .to_account_metas(None);
1809    let data = ClaimFailureAppendArgs {
1810        comp_offset: computation_offset,
1811        mxe_program: mxe_program_id.to_owned(),
1812        chunk,
1813        failure_claim_offset,
1814    }
1815    .data();
1816
1817    Instruction {
1818        program_id: ARCIUM_PROG_ID,
1819        accounts,
1820        data,
1821    }
1822}
1823
1824pub fn claim_failure_finalize_ix(
1825    signer: &Pubkey,
1826    mxe_program_id: &Pubkey,
1827    cluster_offset: u32,
1828    computation_offset: u64,
1829    node_offset: u32,
1830) -> Instruction {
1831    let accounts = ClaimFailureFinalizeAccs {
1832        signer: signer.key(),
1833        failure_acc: failure_claim_acc(mxe_program_id, computation_offset),
1834        executing_pool: execpool_acc(cluster_offset),
1835        mempool: mempool_acc(cluster_offset),
1836        comp: computation_acc(cluster_offset, computation_offset),
1837        cluster_acc: cluster_acc(cluster_offset),
1838        mxe: mxe_acc(mxe_program_id),
1839    }
1840    .to_account_metas(None);
1841    let data = ClaimFailureFinalizeArgs {
1842        comp_offset: computation_offset,
1843        node_offset,
1844        mxe_program: mxe_program_id.to_owned(),
1845    }
1846    .data();
1847
1848    Instruction {
1849        program_id: ARCIUM_PROG_ID,
1850        accounts,
1851        data,
1852    }
1853}
1854
1855pub fn reclaim_expired_computation_fee_ix(
1856    signer: &Pubkey,
1857    mxe_program_id: &Pubkey,
1858    cluster_offset: u32,
1859    computation_offset: u64,
1860) -> Instruction {
1861    let accounts = ReclaimExpiredComputationFeeAccs {
1862        signer: signer.key(),
1863        mxe: mxe_acc(mxe_program_id),
1864        cluster_acc: cluster_acc(cluster_offset),
1865        comp: computation_acc(cluster_offset, computation_offset),
1866        executing_pool: execpool_acc(cluster_offset),
1867        pool_account: fee_pool_acc(),
1868        system_program: SYSTEM_PROGRAM_ID,
1869    }
1870    .to_account_metas(None);
1871    let data = ReclaimExpiredComputationFeeArgs {
1872        comp_offset: computation_offset,
1873        mxe_program: mxe_program_id.to_owned(),
1874    }
1875    .data();
1876
1877    Instruction {
1878        program_id: ARCIUM_PROG_ID,
1879        accounts,
1880        data,
1881    }
1882}
1883
1884pub fn reclaim_failure_rent_idempotent_ix(
1885    signer: &Pubkey,
1886    recipient: &Pubkey,
1887    mxe_program_id: &Pubkey,
1888    computation_offset: u64,
1889) -> Instruction {
1890    let accounts = ReclaimFailureRentIdempotentAccs {
1891        signer: signer.key(),
1892        recipient: recipient.key(),
1893        failure_acc: failure_claim_acc(mxe_program_id, computation_offset),
1894    }
1895    .to_account_metas(None);
1896    let data = ReclaimFailureRentIdempotentArgs {
1897        comp_offset: computation_offset,
1898        mxe_program: mxe_program_id.to_owned(),
1899    }
1900    .data();
1901
1902    Instruction {
1903        program_id: ARCIUM_PROG_ID,
1904        accounts,
1905        data,
1906    }
1907}
1908
1909pub fn update_current_epoch_idempotent_ix() -> Instruction {
1910    let accounts = UpdateCurrentEpochIdempotentAccs { clock: clock_acc() }.to_account_metas(None);
1911    let data = UpdateCurrentEpochIdempotentArgs {}.data();
1912
1913    Instruction {
1914        program_id: ARCIUM_PROG_ID,
1915        accounts,
1916        data,
1917    }
1918}
1919
1920pub fn set_arx_node_config_ix(
1921    signer: &Pubkey,
1922    node_offset: u32,
1923    config: ArxNodeConfig,
1924) -> Instruction {
1925    let accounts = SetArxNodeConfigAccs {
1926        signer: signer.key(),
1927        arx_node_acc: arx_acc(node_offset),
1928    }
1929    .to_account_metas(None);
1930    let data = SetArxNodeConfigArgs {
1931        node_offset,
1932        config,
1933    }
1934    .data();
1935
1936    Instruction {
1937        program_id: ARCIUM_PROG_ID,
1938        accounts,
1939        data,
1940    }
1941}
1942
1943pub fn set_arx_node_metadata_ix(
1944    signer: &Pubkey,
1945    node_offset: u32,
1946    metadata: NodeMetadata,
1947) -> Instruction {
1948    let accounts = SetArxNodeMetadataAccs {
1949        signer: signer.key(),
1950        arx_node_acc: arx_acc(node_offset),
1951    }
1952    .to_account_metas(None);
1953    let data = SetArxNodeMetadataArgs {
1954        node_offset,
1955        meta: metadata,
1956    }
1957    .data();
1958
1959    Instruction {
1960        program_id: ARCIUM_PROG_ID,
1961        accounts,
1962        data,
1963    }
1964}
1965
1966pub fn submit_aggregated_bls_pubkey_ix(
1967    node_authority: &Pubkey,
1968    cluster_offset: u32,
1969    node_offset: u32,
1970    aggregated_bls_pubkey: BN254G2BLSPublicKey,
1971) -> Instruction {
1972    let accounts = SubmitAggregatedBlsPubkeyAccs {
1973        cluster_acc: cluster_acc(cluster_offset),
1974        arx_node_acc: arx_acc(node_offset),
1975        node_authority: node_authority.key(),
1976    }
1977    .to_account_metas(None);
1978
1979    let data = SubmitAggregatedBlsPubkeyArgs {
1980        cluster_id: cluster_offset,
1981        aggregated_bls_pubkey,
1982        node_bump: node_offset,
1983    }
1984    .data();
1985
1986    Instruction {
1987        program_id: ARCIUM_PROG_ID,
1988        accounts,
1989        data,
1990    }
1991}
1992
1993pub fn deactivate_computation_definition_ix(
1994    signer: &Pubkey,
1995    comp_offset: u32,
1996    mxe_program: &Pubkey,
1997) -> Instruction {
1998    let accounts = DeactivateComputationDefinitionAccs {
1999        signer: signer.to_owned(),
2000        mxe: mxe_acc(mxe_program),
2001        comp_def_acc: computation_definition_acc(mxe_program, comp_offset),
2002    }
2003    .to_account_metas(None);
2004    let data = DeactivateComputationDefinitionArgs {
2005        comp_offset,
2006        mxe_program: *mxe_program,
2007    }
2008    .data();
2009
2010    Instruction {
2011        program_id: ARCIUM_PROG_ID,
2012        accounts,
2013        data,
2014    }
2015}
2016
2017pub fn close_computation_definition_ix(
2018    signer: &Pubkey,
2019    comp_offset: u32,
2020    mxe_program: &Pubkey,
2021    cluster_offset: u32,
2022) -> Instruction {
2023    let accounts = CloseComputationDefinitionAccs {
2024        signer: signer.to_owned(),
2025        mxe: mxe_acc(mxe_program),
2026        comp_def_acc: computation_definition_acc(mxe_program, comp_offset),
2027        executing_pool: execpool_acc(cluster_offset),
2028        system_program: SYSTEM_PROGRAM_ID,
2029    }
2030    .to_account_metas(None);
2031    let data = CloseComputationDefinitionArgs {
2032        comp_offset,
2033        mxe_program: *mxe_program,
2034        cluster_offset,
2035    }
2036    .data();
2037
2038    Instruction {
2039        program_id: ARCIUM_PROG_ID,
2040        accounts,
2041        data,
2042    }
2043}
2044
2045pub fn close_computation_definition_buffers_ix(
2046    signer: &Pubkey,
2047    comp_offset: u32,
2048    mxe_program: &Pubkey,
2049    raw_circuit_index: u8,
2050) -> Instruction {
2051    let comp_def_acc = computation_definition_acc(mxe_program, comp_offset);
2052    let accounts = CloseComputationDefinitionBuffersAccs {
2053        signer: signer.to_owned(),
2054        mxe: mxe_acc(mxe_program),
2055        comp_def_acc,
2056        comp_def_raw: raw_circuit_acc(&comp_def_acc, raw_circuit_index),
2057    }
2058    .to_account_metas(None);
2059    let data = CloseComputationDefinitionBuffersArgs {
2060        comp_offset,
2061        mxe_program: *mxe_program,
2062        raw_circuit_index,
2063    }
2064    .data();
2065
2066    Instruction {
2067        program_id: ARCIUM_PROG_ID,
2068        accounts,
2069        data,
2070    }
2071}
2072
2073#[allow(clippy::too_many_arguments)]
2074pub fn close_mxe_ix(
2075    signer: &Pubkey,
2076    mxe_program: &Pubkey,
2077    cluster_offset: u32,
2078    keygen_offset: u64,
2079    key_recovery_init_offset: u64,
2080    kr_init_comp_def_exists: bool,
2081) -> Instruction {
2082    let accounts = CloseMxeAccs {
2083        signer: signer.to_owned(),
2084        mxe_program: *mxe_program,
2085        mxe: mxe_acc(mxe_program),
2086        mxe_keygen_computation: computation_acc(cluster_offset, keygen_offset),
2087        mxe_keygen_comp_def: computation_definition_acc(
2088            mxe_program,
2089            RESERVED_MXE_KEYGEN_COMP_DEF_OFFSET,
2090        ),
2091        mxe_key_recovery_init_comp_def: if kr_init_comp_def_exists {
2092            Some(computation_definition_acc(
2093                mxe_program,
2094                RESERVED_MXE_KEY_RECOVERY_INIT_COMP_DEF_OFFSET,
2095            ))
2096        } else {
2097            None
2098        },
2099        key_recovery_init_computation: Some(computation_acc(
2100            cluster_offset,
2101            key_recovery_init_offset,
2102        )),
2103        recovery_cluster_acc: recovery_cluster_acc(mxe_program),
2104    }
2105    .to_account_metas(None);
2106    let data = CloseMxeArgs {
2107        cluster_offset,
2108        keygen_offset,
2109    }
2110    .data();
2111
2112    Instruction {
2113        program_id: ARCIUM_PROG_ID,
2114        accounts,
2115        data,
2116    }
2117}
2118
2119pub mod staking {
2120    use super::*;
2121    use crate::{
2122        idl::{
2123            arcium::ID as ARCIUM_PROG_ID,
2124            arcium_staking::{
2125                client::{
2126                    accounts::{
2127                        ActivatePrimaryStake as ActivatePrimaryStakeAccs,
2128                        AddPrimaryStakeToLegacyAcc as AddPrimaryStakeToLegacyAccAccs,
2129                        ClaimPrimaryStakeRewards as ClaimPrimaryStakeRewardsAccs,
2130                        CloseDelegatedStake as CloseDelegatedStakeAccs,
2131                        DeactivatePrimaryStake as DeactivatePrimaryStakeAccs,
2132                        DelegateStake as DelegateStakeAccs,
2133                        FinalizeEpochRewards as FinalizeEpochRewardsAccs,
2134                        InitClusterStakeState as InitClusterStakeStateAccs,
2135                        InitDelegatedStakeAcc as InitDelegatedStakeAccs,
2136                        InitMxeRecoveryStakeState as InitMxeRecoveryStakeStateAccs,
2137                        InitPrimaryStake as InitPrimaryStakeAccs,
2138                        InitStakeMasterAcc as InitDelegatedStakeMasterAccs,
2139                        MergeDelegatedStakeAccount as MergeDelegatedStakeAccountAccs,
2140                        ModifyPrimaryStake as ModifyPrimaryStakeAccs,
2141                        SplitDelegatedStakeAccount as SplitDelegatedStakeAccountAccs,
2142                        UndelegateStake as UndelegateStakeAccs,
2143                    },
2144                    args::{
2145                        ActivatePrimaryStake as ActivatePrimaryStakeArgs,
2146                        AddPrimaryStakeToLegacyAcc as AddPrimaryStakeToLegacyAccArgs,
2147                        ClaimPrimaryStakeRewards as ClaimPrimaryStakeRewardsArgs,
2148                        CloseDelegatedStake as CloseDelegatedStakeArgs,
2149                        DeactivatePrimaryStake as DeactivatePrimaryStakeArgs,
2150                        DelegateStake as DelegateStakeArgs,
2151                        FinalizeEpochRewards as FinalizeEpochRewardsArgs,
2152                        InitClusterStakeState as InitClusterStakeStateArgs,
2153                        InitDelegatedStakeAcc as InitDelegatedStakeArgs,
2154                        InitMxeRecoveryStakeState as InitMxeRecoveryStakeStateArgs,
2155                        InitPrimaryStake as InitPrimaryStakeArgs,
2156                        InitStakeMasterAcc as InitDelegatedStakeMasterArgs,
2157                        MergeDelegatedStakeAccount as MergeDelegatedStakeAccountArgs,
2158                        ModifyPrimaryStake as ModifyPrimaryStakeArgs,
2159                        SplitDelegatedStakeAccount as SplitDelegatedStakeAccountArgs,
2160                        UndelegateStake as UndelegateStakeArgs,
2161                    },
2162                },
2163                types::{Epoch, Hash, MTProof, RewardBatch, RewardClaim},
2164                ID as ARCIUM_STAKING_PROG_ID,
2165            },
2166        },
2167        pda::{
2168            arx_acc,
2169            clock_acc,
2170            cluster_acc,
2171            fee_pool_acc,
2172            staking::{
2173                cluster_stake_state_acc,
2174                delegated_stake_acc,
2175                mxe_recovery_stake_state_acc,
2176                primary_stake_acc,
2177                stake_master_acc,
2178                staking_pool_acc,
2179            },
2180            ARCIUM_TOKEN_MINT,
2181        },
2182    };
2183    use anchor_spl::{
2184        associated_token::get_associated_token_address,
2185        token::ID as TOKEN_PROGRAM_ID,
2186    };
2187
2188    pub fn init_primary_stake_acc_ix(
2189        signer: &Pubkey,
2190        amount: u64,
2191        fee_basis_points: u16,
2192    ) -> Instruction {
2193        let primary_stake_acc = primary_stake_acc(signer);
2194        let pool_acc = staking_pool_acc();
2195        let accounts = InitPrimaryStakeAccs {
2196            from: signer.to_owned(),
2197            from_ta: get_associated_token_address(signer, &ARCIUM_TOKEN_MINT),
2198            primary_stake_account: primary_stake_acc.key(),
2199            mint: ARCIUM_TOKEN_MINT,
2200            pool_account: pool_acc,
2201            pool_ata: get_associated_token_address(&pool_acc, &ARCIUM_TOKEN_MINT),
2202            clock: clock_acc(),
2203            system_program: SYSTEM_PROGRAM_ID,
2204            token_program: TOKEN_PROGRAM_ID,
2205        }
2206        .to_account_metas(None);
2207        let data = InitPrimaryStakeArgs {
2208            amount,
2209            fee_basis_points,
2210        }
2211        .data();
2212
2213        Instruction {
2214            program_id: ARCIUM_STAKING_PROG_ID,
2215            accounts,
2216            data,
2217        }
2218    }
2219
2220    /// Create a real-stake `PrimaryStakingAccount` for `signer` (`amount >= MIN_SELF_DELEGATION`,
2221    /// transferred from `signer`'s ARCIUM ATA) for a legacy node / recovery peer that the arcium
2222    /// migration instructions then bind. The migration counterpart of `init_primary_stake_acc_ix`.
2223    pub fn add_primary_stake_to_legacy_acc_ix(
2224        signer: &Pubkey,
2225        amount: u64,
2226        fee_basis_points: u16,
2227    ) -> Instruction {
2228        let pool_acc = staking_pool_acc();
2229        let accounts = AddPrimaryStakeToLegacyAccAccs {
2230            from: signer.to_owned(),
2231            from_ta: get_associated_token_address(signer, &ARCIUM_TOKEN_MINT),
2232            primary_stake_account: primary_stake_acc(signer),
2233            mint: ARCIUM_TOKEN_MINT,
2234            pool_account: pool_acc,
2235            pool_ata: get_associated_token_address(&pool_acc, &ARCIUM_TOKEN_MINT),
2236            clock: clock_acc(),
2237            system_program: SYSTEM_PROGRAM_ID,
2238            token_program: TOKEN_PROGRAM_ID,
2239        }
2240        .to_account_metas(None);
2241        let data = AddPrimaryStakeToLegacyAccArgs {
2242            amount,
2243            fee_basis_points,
2244        }
2245        .data();
2246
2247        Instruction {
2248            program_id: ARCIUM_STAKING_PROG_ID,
2249            accounts,
2250            data,
2251        }
2252    }
2253
2254    pub fn activate_primary_stake_acc_ix(signer: &Pubkey, lockup_epochs: u64) -> Instruction {
2255        let accounts = ActivatePrimaryStakeAccs {
2256            signer: signer.to_owned(),
2257            primary_stake_account: primary_stake_acc(signer),
2258            clock: clock_acc(),
2259        }
2260        .to_account_metas(None);
2261        let data = ActivatePrimaryStakeArgs {
2262            lockup_epochs: Epoch(lockup_epochs),
2263        }
2264        .data();
2265
2266        Instruction {
2267            program_id: ARCIUM_STAKING_PROG_ID,
2268            accounts,
2269            data,
2270        }
2271    }
2272
2273    pub fn deactivate_primary_stake_acc_ix(
2274        signer: &Pubkey,
2275        arx_node_offset: Option<u32>,
2276    ) -> Instruction {
2277        let accounts = DeactivatePrimaryStakeAccs {
2278            signer: signer.to_owned(),
2279            primary_stake_account: primary_stake_acc(signer),
2280            clock: clock_acc(),
2281        }
2282        .to_account_metas(None);
2283        let data = DeactivatePrimaryStakeArgs {
2284            node_offset: arx_node_offset,
2285        }
2286        .data();
2287
2288        Instruction {
2289            program_id: ARCIUM_STAKING_PROG_ID,
2290            accounts,
2291            data,
2292        }
2293    }
2294
2295    /// Modify the amount in `signer`'s primary stake account by `diff` base units. A positive
2296    /// `diff` transfers ARX from `signer`'s ATA into the pool (adding stake); a negative `diff`
2297    /// withdraws (the lockup must not be `ActiveLocked` and the result must stay above the
2298    /// self-delegation floor). The change is enqueued and matures in a later epoch. The primary
2299    /// must be settled to the current epoch first (call `finalize_epoch_rewards` to catch up).
2300    ///
2301    /// `arx_node` / `mempool` are only consulted on withdrawals: when the stake is bound to a node
2302    /// the program reads the node (and, if it's seated in a cluster, that cluster's mempool) to
2303    /// enforce the cluster's per-mempool-size minimum primary stake. Pass `arx_node = Some(node)`
2304    /// when the stake's binding is `Node(node)`, and `mempool = Some(mempool_acc(cluster_offset))`
2305    /// when that node belongs to a cluster; both may be `None` for deposits or unbound stakes.
2306    pub fn modify_primary_stake_ix(
2307        signer: &Pubkey,
2308        diff: i64,
2309        arx_node: Option<Pubkey>,
2310        mempool: Option<Pubkey>,
2311    ) -> Instruction {
2312        let pool_acc = staking_pool_acc();
2313        let accounts = ModifyPrimaryStakeAccs {
2314            signer: signer.to_owned(),
2315            signer_ta: get_associated_token_address(signer, &ARCIUM_TOKEN_MINT),
2316            primary_stake_account: primary_stake_acc(signer),
2317            mint: ARCIUM_TOKEN_MINT,
2318            pool_account: pool_acc,
2319            pool_ata: get_associated_token_address(&pool_acc, &ARCIUM_TOKEN_MINT),
2320            clock: clock_acc(),
2321            arx_node,
2322            mempool,
2323            system_program: SYSTEM_PROGRAM_ID,
2324            token_program: TOKEN_PROGRAM_ID,
2325        }
2326        .to_account_metas(None);
2327        let data = ModifyPrimaryStakeArgs { diff }.data();
2328
2329        Instruction {
2330            program_id: ARCIUM_STAKING_PROG_ID,
2331            accounts,
2332            data,
2333        }
2334    }
2335
2336    pub fn finalize_epoch_rewards_ix(
2337        signer: &Pubkey,
2338        primary_stake_owner: &Pubkey,
2339        cluster_offset: u32,
2340        node_offset: u32,
2341    ) -> Instruction {
2342        let pool_account = staking_pool_acc();
2343        let mint = ARCIUM_TOKEN_MINT;
2344        let primary_stake_acc = primary_stake_acc(primary_stake_owner);
2345
2346        let accounts = FinalizeEpochRewardsAccs {
2347            signer: signer.key(),
2348            primary_stake_owner: primary_stake_owner.key(),
2349            primary_stake_owner_ata: get_associated_token_address(primary_stake_owner, &mint),
2350            primary_stake_account: primary_stake_acc,
2351            arx_node_acc: arx_acc(node_offset),
2352            cluster_acc: cluster_acc(cluster_offset),
2353            fee_pool: fee_pool_acc(),
2354            pool_account,
2355            pool_ata: get_associated_token_address(&pool_account, &mint),
2356            clock: clock_acc(),
2357            cluster_stake_state: cluster_stake_state_acc(cluster_offset),
2358            arcium_program: ARCIUM_PROG_ID,
2359            token_program: TOKEN_PROGRAM_ID,
2360            system_program: SYSTEM_PROGRAM_ID,
2361        }
2362        .to_account_metas(None);
2363        let data = FinalizeEpochRewardsArgs {
2364            cluster_offset,
2365            node_offset,
2366        }
2367        .data();
2368
2369        Instruction {
2370            program_id: ARCIUM_STAKING_PROG_ID,
2371            accounts,
2372            data,
2373        }
2374    }
2375
2376    /// Height of the rewards compressed merkle tree (`REWARDS_MT_HEIGHT` on-chain). The proof's
2377    /// opening carries exactly one sibling hash per level.
2378    pub const REWARDS_MT_HEIGHT: usize = 15;
2379
2380    /// Build a `claim_primary_stake_rewards` instruction. `signer` must be the primary stake
2381    /// owner — the account is seeded `[PrimaryStakingAccount::SEED, signer]` — and `destination`
2382    /// receives the claimed lamports.
2383    ///
2384    /// `leaf_index` + `opening` are the Merkle proof of `claim` against the primary's on-chain
2385    /// `rewards_mt.root`; the program re-verifies them before paying out. The proof is normally
2386    /// obtained from a rewards-server (which is the only place that stores the historical leaves),
2387    /// or reconstructed client-side via [`crate::staking_rewards`].
2388    ///
2389    /// Claims must be submitted in strictly increasing epoch order: the program requires
2390    /// `claim.epoch == primary.claimed_rewards + 1` (or any epoch when nothing has been claimed
2391    /// yet). The batching rate is 1, so exactly one claim is settled per instruction.
2392    pub fn claim_primary_stake_rewards_ix(
2393        signer: &Pubkey,
2394        destination: &Pubkey,
2395        leaf_index: u16,
2396        opening: [[u8; 32]; REWARDS_MT_HEIGHT],
2397        claim: RewardClaim,
2398    ) -> Instruction {
2399        let accounts = ClaimPrimaryStakeRewardsAccs {
2400            signer: signer.to_owned(),
2401            destination: destination.to_owned(),
2402            primary_stake_account: primary_stake_acc(signer),
2403            pool_account: staking_pool_acc(),
2404        }
2405        .to_account_metas(None);
2406        let data = ClaimPrimaryStakeRewardsArgs {
2407            proof: MTProof {
2408                leaf_index,
2409                opening: opening.map(Hash),
2410            },
2411            claims: RewardBatch { claims: [claim] },
2412        }
2413        .data();
2414
2415        Instruction {
2416            program_id: ARCIUM_STAKING_PROG_ID,
2417            accounts,
2418            data,
2419        }
2420    }
2421
2422    pub fn init_cluster_stake_state_ix(payer: &Pubkey, cluster_offset: u32) -> Instruction {
2423        let accounts = InitClusterStakeStateAccs {
2424            payer: payer.to_owned(),
2425            cluster_stake_state: cluster_stake_state_acc(cluster_offset),
2426            system_program: SYSTEM_PROGRAM_ID,
2427        }
2428        .to_account_metas(None);
2429        let data = InitClusterStakeStateArgs { cluster_offset }.data();
2430
2431        Instruction {
2432            program_id: ARCIUM_STAKING_PROG_ID,
2433            accounts,
2434            data,
2435        }
2436    }
2437
2438    pub fn init_mxe_recovery_stake_state_ix(payer: &Pubkey, mxe_program: &Pubkey) -> Instruction {
2439        let accounts = InitMxeRecoveryStakeStateAccs {
2440            payer: payer.to_owned(),
2441            mxe_recovery_stake_state: mxe_recovery_stake_state_acc(mxe_program),
2442            instructions_sysvar: INSTRUCTIONS_SYSVAR_ID,
2443            system_program: SYSTEM_PROGRAM_ID,
2444        }
2445        .to_account_metas(None);
2446        let data = InitMxeRecoveryStakeStateArgs {
2447            mxe_program: *mxe_program,
2448        }
2449        .data();
2450
2451        Instruction {
2452            program_id: ARCIUM_STAKING_PROG_ID,
2453            accounts,
2454            data,
2455        }
2456    }
2457
2458    pub fn init_delegated_stake_master_acc_ix(signer: &Pubkey, owner: &Pubkey) -> Instruction {
2459        let accounts = InitDelegatedStakeMasterAccs {
2460            signer: signer.to_owned(),
2461            master_stake_account: stake_master_acc(owner),
2462            owner: owner.to_owned(),
2463            system_program: SYSTEM_PROGRAM_ID,
2464        }
2465        .to_account_metas(None);
2466        let data = InitDelegatedStakeMasterArgs {}.data();
2467
2468        Instruction {
2469            program_id: ARCIUM_STAKING_PROG_ID,
2470            accounts,
2471            data,
2472        }
2473    }
2474
2475    pub fn init_delegated_stake_acc_ix(
2476        signer: &Pubkey,
2477        stake_offset: u128,
2478        amount: u64,
2479    ) -> Instruction {
2480        let accounts = InitDelegatedStakeAccs {
2481            from: signer.to_owned(),
2482            from_ata: get_associated_token_address(signer, &ARCIUM_TOKEN_MINT),
2483            master_stake_account: stake_master_acc(signer),
2484            user_stake_account: delegated_stake_acc(stake_offset),
2485            mint: ARCIUM_TOKEN_MINT,
2486            pool_account: staking_pool_acc(),
2487            pool_ata: get_associated_token_address(&staking_pool_acc(), &ARCIUM_TOKEN_MINT),
2488            system_program: SYSTEM_PROGRAM_ID,
2489            token_program: TOKEN_PROGRAM_ID,
2490        }
2491        .to_account_metas(None);
2492        let data = InitDelegatedStakeArgs {
2493            stake_offset,
2494            amount,
2495        }
2496        .data();
2497
2498        Instruction {
2499            program_id: ARCIUM_STAKING_PROG_ID,
2500            accounts,
2501            data,
2502        }
2503    }
2504
2505    pub fn delegate_stake_ix(
2506        signer: &Pubkey,
2507        stake_offset: u128,
2508        primary_stake_owner: &Pubkey,
2509        lockup_epochs: u64,
2510    ) -> Instruction {
2511        let accounts = DelegateStakeAccs {
2512            signer: signer.to_owned(),
2513            primary_acc_owner: primary_stake_owner.to_owned(),
2514            user_stake_account: delegated_stake_acc(stake_offset),
2515            primary: primary_stake_acc(primary_stake_owner),
2516            clock: clock_acc(),
2517            system_program: SYSTEM_PROGRAM_ID,
2518        }
2519        .to_account_metas(None);
2520        let data = DelegateStakeArgs {
2521            stake_offset,
2522            lockup_epochs: Epoch(lockup_epochs),
2523        }
2524        .data();
2525
2526        Instruction {
2527            program_id: ARCIUM_STAKING_PROG_ID,
2528            accounts,
2529            data,
2530        }
2531    }
2532
2533    pub fn undelegate_stake_ix(
2534        signer: &Pubkey,
2535        stake_offset: u128,
2536        primary_stake_owner: &Pubkey,
2537    ) -> Instruction {
2538        let accounts = UndelegateStakeAccs {
2539            signer: signer.to_owned(),
2540            user_stake_account: delegated_stake_acc(stake_offset),
2541            primary: primary_stake_acc(primary_stake_owner),
2542            clock: clock_acc(),
2543        }
2544        .to_account_metas(None);
2545        let data = UndelegateStakeArgs { stake_offset }.data();
2546
2547        Instruction {
2548            program_id: ARCIUM_STAKING_PROG_ID,
2549            accounts,
2550            data,
2551        }
2552    }
2553
2554    /// Split a delegated stake account into two.
2555    /// * `primary_stake_owner_target` - The owner of the primary stake account we're delegating to.
2556    pub fn split_delegated_stake_account_ix(
2557        _primary_stake_owner_target: &Pubkey,
2558        delegation_authority: &Pubkey,
2559        withdrawal_authority: &Pubkey,
2560        stake_offset: u128,
2561        stake_offset_new: u128,
2562        new_acc_balance: u64,
2563    ) -> Instruction {
2564        let accounts = SplitDelegatedStakeAccountAccs {
2565            delegation_authority: delegation_authority.to_owned(),
2566            withdrawal_authority: withdrawal_authority.to_owned(),
2567            delegation_master: stake_master_acc(delegation_authority),
2568            withdrawal_master: stake_master_acc(withdrawal_authority),
2569            old_stake_account: delegated_stake_acc(stake_offset),
2570            new_stake_account: delegated_stake_acc(stake_offset_new),
2571            system_program: SYSTEM_PROGRAM_ID,
2572        }
2573        .to_account_metas(None);
2574        let data = SplitDelegatedStakeAccountArgs {
2575            new_acc_balance,
2576            _stake_offset: stake_offset,
2577            _stake_offset_new: stake_offset_new,
2578        }
2579        .data();
2580
2581        Instruction {
2582            program_id: ARCIUM_STAKING_PROG_ID,
2583            accounts,
2584            data,
2585        }
2586    }
2587
2588    /// Split a delegated stake account into two.
2589    /// * `primary_stake_owner_target` - The owner of the primary stake account we're delegating to.
2590    pub fn merge_delegated_stake_account_ix(
2591        _primary_stake_owner_target: &Pubkey,
2592        delegation_authority: &Pubkey,
2593        withdrawal_authority: &Pubkey,
2594        stake_offset_keep: u128,
2595        stake_offset_close: u128,
2596    ) -> Instruction {
2597        let accounts = MergeDelegatedStakeAccountAccs {
2598            delegation_authority: delegation_authority.to_owned(),
2599            withdrawal_authority: withdrawal_authority.to_owned(),
2600            delegation_master: stake_master_acc(delegation_authority),
2601            withdrawal_master: stake_master_acc(withdrawal_authority),
2602            stake_acc_to_keep: delegated_stake_acc(stake_offset_keep),
2603            stake_acc_to_close: delegated_stake_acc(stake_offset_close),
2604            system_program: SYSTEM_PROGRAM_ID,
2605        }
2606        .to_account_metas(None);
2607        let data = MergeDelegatedStakeAccountArgs {
2608            _stake_offset_keep: stake_offset_keep,
2609            _stake_offset_close: stake_offset_close,
2610        }
2611        .data();
2612
2613        Instruction {
2614            program_id: ARCIUM_STAKING_PROG_ID,
2615            accounts,
2616            data,
2617        }
2618    }
2619
2620    pub fn close_delegated_stake_ix(
2621        signer: &Pubkey,
2622        delegation_owner: &Pubkey,
2623        stake_offset: u128,
2624        primary_stake_owner: Option<&Pubkey>,
2625    ) -> Instruction {
2626        let accounts = CloseDelegatedStakeAccs {
2627            signer: signer.to_owned(),
2628            signer_ata: get_associated_token_address(signer, &ARCIUM_TOKEN_MINT),
2629            withdrawal_master: stake_master_acc(signer),
2630            delegation_master: stake_master_acc(delegation_owner),
2631            delegation_owner: delegation_owner.to_owned(),
2632            user_stake_account: delegated_stake_acc(stake_offset),
2633            mint: ARCIUM_TOKEN_MINT,
2634            pool_account: staking_pool_acc(),
2635            pool_ata: get_associated_token_address(&staking_pool_acc(), &ARCIUM_TOKEN_MINT),
2636            clock: clock_acc(),
2637            system_program: SYSTEM_PROGRAM_ID,
2638            token_program: TOKEN_PROGRAM_ID,
2639            primary: primary_stake_owner.map(primary_stake_acc),
2640        }
2641        .to_account_metas(None);
2642        let data = CloseDelegatedStakeArgs { stake_offset }.data();
2643
2644        Instruction {
2645            program_id: ARCIUM_STAKING_PROG_ID,
2646            accounts,
2647            data,
2648        }
2649    }
2650}
2651
2652#[cfg(feature = "permissioned-mainnet")]
2653pub mod permissioned_mainnet {
2654    use crate::{
2655        idl::arcium::{
2656            client::{
2657                accounts::{
2658                    AddPermissionedRecoveryPeers as AddPermissionedRecoveryPeersAccs,
2659                    ClosePermissionedRecoveryPeersAccount as ClosePermissionedRecoveryPeersAccountAccs,
2660                    InitPermissionedRecoveryPeersAccount as InitPermissionedRecoveryPeersAccountAccs,
2661                    RemovePermissionedRecoveryPeers as RemovePermissionedRecoveryPeersAccs,
2662                },
2663                args::{
2664                    AddPermissionedRecoveryPeers as AddPermissionedRecoveryPeersArgs,
2665                    ClosePermissionedRecoveryPeersAccount as ClosePermissionedRecoveryPeersAccountArgs,
2666                    InitPermissionedRecoveryPeersAccount as InitPermissionedRecoveryPeersAccountArgs,
2667                    RemovePermissionedRecoveryPeers as RemovePermissionedRecoveryPeersArgs,
2668                },
2669            },
2670            ID as ARCIUM_PROG_ID,
2671        },
2672        instruction::SYSTEM_PROGRAM_ID,
2673        pda::permissioned_recovery_peers_acc,
2674    };
2675    use anchor_lang::{
2676        prelude::{bpf_loader_upgradeable, Pubkey},
2677        InstructionData,
2678        ToAccountMetas,
2679    };
2680    use solana_program::instruction::Instruction;
2681
2682    pub fn init_permissioned_recovery_peers_acc_ix(signer: &Pubkey) -> Instruction {
2683        let (program_data, _) =
2684            Pubkey::find_program_address(&[ARCIUM_PROG_ID.as_ref()], &bpf_loader_upgradeable::id());
2685
2686        let accounts = InitPermissionedRecoveryPeersAccountAccs {
2687            signer: signer.to_owned(),
2688            permissioned_recovery_peers_acc: permissioned_recovery_peers_acc(),
2689            program_data,
2690            system_program: SYSTEM_PROGRAM_ID,
2691        }
2692        .to_account_metas(None);
2693        let data = InitPermissionedRecoveryPeersAccountArgs.data();
2694
2695        Instruction {
2696            program_id: ARCIUM_PROG_ID,
2697            accounts,
2698            data,
2699        }
2700    }
2701
2702    pub fn close_permissioned_recovery_peers_acc_ix(signer: &Pubkey) -> Instruction {
2703        let (program_data, _) =
2704            Pubkey::find_program_address(&[ARCIUM_PROG_ID.as_ref()], &bpf_loader_upgradeable::id());
2705
2706        let accounts = ClosePermissionedRecoveryPeersAccountAccs {
2707            signer: signer.to_owned(),
2708            permissioned_recovery_peers_acc: permissioned_recovery_peers_acc(),
2709            program_data,
2710            system_program: SYSTEM_PROGRAM_ID,
2711        }
2712        .to_account_metas(None);
2713        let data = ClosePermissionedRecoveryPeersAccountArgs.data();
2714
2715        Instruction {
2716            program_id: ARCIUM_PROG_ID,
2717            accounts,
2718            data,
2719        }
2720    }
2721
2722    pub fn add_permissioned_recovery_peers_ix(signer: &Pubkey, peers: Vec<Pubkey>) -> Instruction {
2723        let (program_data, _) =
2724            Pubkey::find_program_address(&[ARCIUM_PROG_ID.as_ref()], &bpf_loader_upgradeable::id());
2725
2726        let accounts = AddPermissionedRecoveryPeersAccs {
2727            signer: signer.to_owned(),
2728            permissioned_recovery_peers_acc: permissioned_recovery_peers_acc(),
2729            program_data,
2730            system_program: SYSTEM_PROGRAM_ID,
2731        }
2732        .to_account_metas(None);
2733        let data = AddPermissionedRecoveryPeersArgs { peers }.data();
2734
2735        Instruction {
2736            program_id: ARCIUM_PROG_ID,
2737            accounts,
2738            data,
2739        }
2740    }
2741
2742    pub fn remove_permissioned_recovery_peers_ix(
2743        signer: &Pubkey,
2744        peers: Vec<Pubkey>,
2745    ) -> Instruction {
2746        let (program_data, _) =
2747            Pubkey::find_program_address(&[ARCIUM_PROG_ID.as_ref()], &bpf_loader_upgradeable::id());
2748
2749        let accounts = RemovePermissionedRecoveryPeersAccs {
2750            signer: signer.to_owned(),
2751            permissioned_recovery_peers_acc: permissioned_recovery_peers_acc(),
2752            program_data,
2753            system_program: SYSTEM_PROGRAM_ID,
2754        }
2755        .to_account_metas(None);
2756        let data = RemovePermissionedRecoveryPeersArgs { peers }.data();
2757
2758        Instruction {
2759            program_id: ARCIUM_PROG_ID,
2760            accounts,
2761            data,
2762        }
2763    }
2764}