Skip to main content

jito_restaking_cli/
restaking_handler.rs

1use std::str::FromStr;
2
3use anyhow::{anyhow, Result};
4use borsh::BorshDeserialize;
5use jito_restaking_client::{
6    instructions::{
7        CooldownNcnVaultTicketBuilder, CooldownOperatorVaultTicketBuilder, InitializeConfigBuilder,
8        InitializeNcnBuilder, InitializeNcnOperatorStateBuilder, InitializeNcnVaultTicketBuilder,
9        InitializeOperatorBuilder, InitializeOperatorVaultTicketBuilder,
10        NcnCooldownOperatorBuilder, NcnDelegateTokenAccountBuilder, NcnSetAdminBuilder,
11        NcnSetSecondaryAdminBuilder, NcnWarmupOperatorBuilder, OperatorCooldownNcnBuilder,
12        OperatorDelegateTokenAccountBuilder, OperatorSetAdminBuilder, OperatorSetFeeBuilder,
13        OperatorSetSecondaryAdminBuilder, OperatorWarmupNcnBuilder, SetConfigAdminBuilder,
14        WarmupNcnVaultTicketBuilder, WarmupOperatorVaultTicketBuilder,
15    },
16    types::{NcnAdminRole, OperatorAdminRole},
17};
18use jito_restaking_client_common::log::PrettyDisplay;
19use jito_restaking_core::{
20    config::Config, ncn::Ncn, ncn_operator_state::NcnOperatorState,
21    ncn_vault_ticket::NcnVaultTicket, operator::Operator,
22    operator_vault_ticket::OperatorVaultTicket,
23};
24use log::info;
25use solana_program::pubkey::Pubkey;
26use solana_sdk::signature::{read_keypair_file, Keypair, Signer};
27use spl_associated_token_account::{
28    get_associated_token_address, instruction::create_associated_token_account_idempotent,
29};
30
31use crate::{
32    cli_config::CliConfig,
33    cli_signer::CliSigner,
34    restaking::{ConfigActions, NcnActions, OperatorActions, RestakingCommands},
35    CliHandler,
36};
37
38pub struct RestakingCliHandler {
39    /// The configuration of CLI
40    cli_config: CliConfig,
41
42    /// The Pubkey of Jito Restaking Program ID
43    restaking_program_id: Pubkey,
44
45    /// The Pubkey of Jito Vault Program ID
46    vault_program_id: Pubkey,
47
48    /// This will print out the raw TX instead of running it
49    print_tx: bool,
50
51    /// This will print out the account information in JSON format
52    print_json: bool,
53
54    /// This will print out the account information in JSON format with reserved space
55    print_json_with_reserves: bool,
56}
57
58impl CliHandler for RestakingCliHandler {
59    fn cli_config(&self) -> &CliConfig {
60        &self.cli_config
61    }
62
63    fn print_tx(&self) -> bool {
64        self.print_tx
65    }
66
67    fn print_json(&self) -> bool {
68        self.print_json
69    }
70
71    fn print_json_with_reserves(&self) -> bool {
72        self.print_json_with_reserves
73    }
74}
75
76impl RestakingCliHandler {
77    pub const fn new(
78        cli_config: CliConfig,
79        restaking_program_id: Pubkey,
80        vault_program_id: Pubkey,
81        print_tx: bool,
82        print_json: bool,
83        print_json_with_reserves: bool,
84    ) -> Self {
85        Self {
86            cli_config,
87            restaking_program_id,
88            vault_program_id,
89            print_tx,
90            print_json,
91            print_json_with_reserves,
92        }
93    }
94
95    #[allow(clippy::future_not_send)]
96    pub async fn handle(&self, action: RestakingCommands) -> Result<()> {
97        match action {
98            RestakingCommands::Config {
99                action: ConfigActions::Initialize,
100            } => self.initialize_config().await,
101            RestakingCommands::Config {
102                action: ConfigActions::Get,
103            } => self.get_config().await,
104            RestakingCommands::Config {
105                action: ConfigActions::SetAdmin { new_admin },
106            } => self.set_config_admin(new_admin).await,
107            RestakingCommands::Ncn {
108                action:
109                    NcnActions::Initialize {
110                        path_to_base_keypair,
111                    },
112            } => self.initialize_ncn(path_to_base_keypair).await,
113            RestakingCommands::Ncn {
114                action: NcnActions::InitializeNcnOperatorState { ncn, operator },
115            } => self.initialize_ncn_operator_state(ncn, operator).await,
116            RestakingCommands::Ncn {
117                action: NcnActions::NcnWarmupOperator { ncn, operator },
118            } => self.ncn_warmup_operator(ncn, operator).await,
119            RestakingCommands::Ncn {
120                action: NcnActions::NcnCooldownOperator { ncn, operator },
121            } => self.ncn_cooldown_operator(ncn, operator).await,
122            RestakingCommands::Ncn {
123                action: NcnActions::InitializeNcnVaultTicket { ncn, vault },
124            } => self.initialize_ncn_vault_ticket(ncn, vault).await,
125            RestakingCommands::Ncn {
126                action: NcnActions::WarmupNcnVaultTicket { ncn, vault },
127            } => self.warmup_ncn_vault_ticket(ncn, vault).await,
128            RestakingCommands::Ncn {
129                action: NcnActions::CooldownNcnVaultTicket { ncn, vault },
130            } => self.cooldown_ncn_vault_ticket(ncn, vault).await,
131            RestakingCommands::Ncn {
132                action:
133                    NcnActions::NcnDelegateTokenAccount {
134                        ncn,
135                        delegate,
136                        token_mint,
137                        should_create_token_account,
138                    },
139            } => {
140                self.ncn_delegate_token_account(
141                    ncn,
142                    delegate,
143                    token_mint,
144                    should_create_token_account,
145                )
146                .await
147            }
148            RestakingCommands::Ncn {
149                action: NcnActions::Get { pubkey },
150            } => self.get_ncn(pubkey).await,
151            RestakingCommands::Ncn {
152                action: NcnActions::List,
153            } => self.list_ncn().await,
154            RestakingCommands::Ncn {
155                action: NcnActions::ListNcnOperatorState { ncn },
156            } => self.list_ncn_operator_state(Some(&ncn), None).await,
157            RestakingCommands::Ncn {
158                action: NcnActions::ListNcnVaultTicket { ncn },
159            } => self.list_ncn_vault_ticket(ncn).await,
160            RestakingCommands::Ncn {
161                action:
162                    NcnActions::NcnSetAdmin {
163                        ncn,
164                        old_admin_keypair,
165                        new_admin_keypair,
166                    },
167            } => {
168                self.ncn_set_admin(ncn, &old_admin_keypair, &new_admin_keypair)
169                    .await
170            }
171            RestakingCommands::Ncn {
172                action:
173                    NcnActions::NcnSetSecondaryAdmin {
174                        ncn,
175                        new_admin,
176                        set_operator_admin,
177                        set_vault_admin,
178                        set_slasher_admin,
179                        set_delegate_admin,
180                        set_metadata_admin,
181                        set_weight_table_admin,
182                        set_ncn_program_admin,
183                    },
184            } => {
185                self.ncn_set_secondary_admin(
186                    &ncn,
187                    &new_admin,
188                    set_operator_admin,
189                    set_vault_admin,
190                    set_slasher_admin,
191                    set_delegate_admin,
192                    set_metadata_admin,
193                    set_weight_table_admin,
194                    set_ncn_program_admin,
195                )
196                .await
197            }
198            RestakingCommands::Operator {
199                action: OperatorActions::Initialize { operator_fee_bps },
200            } => self.initialize_operator(operator_fee_bps).await,
201            RestakingCommands::Operator {
202                action: OperatorActions::InitializeOperatorVaultTicket { operator, vault },
203            } => self.initialize_operator_vault_ticket(operator, vault).await,
204            RestakingCommands::Operator {
205                action: OperatorActions::WarmupOperatorVaultTicket { operator, vault },
206            } => self.warmup_operator_vault_ticket(operator, vault).await,
207            RestakingCommands::Operator {
208                action: OperatorActions::CooldownOperatorVaultTicket { operator, vault },
209            } => self.cooldown_operator_vault_ticket(operator, vault).await,
210            RestakingCommands::Operator {
211                action: OperatorActions::OperatorWarmupNcn { operator, ncn },
212            } => self.operator_warmup_ncn(operator, ncn).await,
213            RestakingCommands::Operator {
214                action: OperatorActions::OperatorCooldownNcn { operator, ncn },
215            } => self.operator_cooldown_ncn(operator, ncn).await,
216            RestakingCommands::Operator {
217                action:
218                    OperatorActions::OperatorSetAdmin {
219                        operator,
220                        old_admin_keypair,
221                        new_admin_keypair,
222                    },
223            } => {
224                self.operator_set_admin(&operator, &old_admin_keypair, &new_admin_keypair)
225                    .await
226            }
227            RestakingCommands::Operator {
228                action:
229                    OperatorActions::OperatorSetSecondaryAdmin {
230                        operator,
231                        new_admin,
232                        set_ncn_admin,
233                        set_vault_admin,
234                        set_voter_admin,
235                        set_delegate_admin,
236                        set_metadata_admin,
237                    },
238            } => {
239                self.operator_set_secondary_admin(
240                    operator,
241                    new_admin,
242                    set_ncn_admin,
243                    set_vault_admin,
244                    set_voter_admin,
245                    set_delegate_admin,
246                    set_metadata_admin,
247                )
248                .await
249            }
250            RestakingCommands::Operator {
251                action:
252                    OperatorActions::OperatorSetFees {
253                        operator,
254                        operator_fee_bps,
255                    },
256            } => self.operator_set_fee(operator, operator_fee_bps).await,
257            RestakingCommands::Operator {
258                action:
259                    OperatorActions::OperatorDelegateTokenAccount {
260                        operator,
261                        delegate,
262                        token_mint,
263                        should_create_token_account,
264                    },
265            } => {
266                self.operator_delegate_token_account(
267                    operator,
268                    delegate,
269                    token_mint,
270                    should_create_token_account,
271                )
272                .await
273            }
274            RestakingCommands::Operator {
275                action: OperatorActions::Get { pubkey },
276            } => self.get_operator(pubkey).await,
277            RestakingCommands::Operator {
278                action: OperatorActions::List,
279            } => self.list_operator().await,
280            RestakingCommands::Operator {
281                action: OperatorActions::ListOperatorVaultTicket { operator },
282            } => self.list_operator_vault_ticket(&operator).await,
283            RestakingCommands::Operator {
284                action: OperatorActions::ListNcnOperatorState { operator },
285            } => self.list_ncn_operator_state(None, Some(&operator)).await,
286        }
287    }
288
289    /// Sets the primary admin for an NCN
290    ///
291    /// This function transfers administrative control of an NCN from the current admin
292    /// to a new admin. It supports both file-based keypairs and hardware wallets (USB devices like
293    /// ledger) for both the old and new admin. The function builds and processes a transaction
294    /// that updates the admin public key in the NCN account.
295    #[allow(clippy::future_not_send)]
296    async fn ncn_set_admin(
297        &self,
298        ncn: Pubkey,
299        old_admin_keypair: &str,
300        new_admin_keypair: &str,
301    ) -> Result<()> {
302        let mut old_admin_owned = None;
303        let mut new_admin_owned = None;
304
305        let old_admin_signer = self.resolve_keypair(old_admin_keypair, &mut old_admin_owned)?;
306        let new_admin_signer = self.resolve_keypair(new_admin_keypair, &mut new_admin_owned)?;
307
308        let mut ix_builder = NcnSetAdminBuilder::new();
309        ix_builder
310            .ncn(ncn)
311            .old_admin(old_admin_signer.pubkey())
312            .new_admin(new_admin_signer.pubkey());
313        let mut ix = ix_builder.instruction();
314        ix.program_id = self.restaking_program_id;
315
316        info!("Setting NCN admin to {}", new_admin_signer.pubkey());
317
318        self.process_transaction(
319            &[ix],
320            &new_admin_signer.pubkey(),
321            &[new_admin_signer, old_admin_signer],
322        )
323        .await?;
324
325        if !self.print_tx {
326            let account = self
327                .get_account::<jito_restaking_client::accounts::Ncn>(&ncn)
328                .await?;
329            info!("{}", account.pretty_display());
330        }
331
332        Ok(())
333    }
334
335    /// Sets secondary admin roles for NCN
336    ///
337    /// This function allows assigning a new administrator to various administrative roles
338    /// for a specific NCN. Multiple roles can be assigned in a single call by enabling the
339    /// corresponding boolean flags.
340    #[allow(clippy::too_many_arguments, clippy::future_not_send)]
341    async fn ncn_set_secondary_admin(
342        &self,
343        ncn: &str,
344        new_admin: &str,
345        set_operator_admin: bool,
346        set_vault_admin: bool,
347        set_slasher_admin: bool,
348        set_delegate_admin: bool,
349        set_metadata_admin: bool,
350        set_weight_table_admin: bool,
351        set_ncn_program_admin: bool,
352    ) -> Result<()> {
353        let signer = self
354            .cli_config
355            .signer
356            .as_ref()
357            .ok_or_else(|| anyhow!("No signer"))?;
358
359        let ncn = Pubkey::from_str(ncn)?;
360        let new_admin = Pubkey::from_str(new_admin)?;
361
362        let mut roles: Vec<NcnAdminRole> = vec![];
363        if set_operator_admin {
364            roles.push(NcnAdminRole::OperatorAdmin);
365        }
366        if set_vault_admin {
367            roles.push(NcnAdminRole::VaultAdmin);
368        }
369        if set_slasher_admin {
370            roles.push(NcnAdminRole::SlasherAdmin);
371        }
372        if set_delegate_admin {
373            roles.push(NcnAdminRole::DelegateAdmin);
374        }
375        if set_metadata_admin {
376            roles.push(NcnAdminRole::MetadataAdmin);
377        }
378        if set_weight_table_admin {
379            roles.push(NcnAdminRole::WeightTableAdmin);
380        }
381        if set_ncn_program_admin {
382            roles.push(NcnAdminRole::NcnProgramAdmin);
383        }
384
385        for role in roles.iter() {
386            let mut ix_builder = NcnSetSecondaryAdminBuilder::new();
387            ix_builder
388                .new_admin(new_admin)
389                .ncn(ncn)
390                .admin(signer.pubkey())
391                .ncn_admin_role(*role)
392                .instruction();
393            let mut ix = ix_builder.instruction();
394            ix.program_id = self.restaking_program_id;
395
396            info!("Setting {:?} Admin to {} for NCN {}", role, new_admin, ncn);
397
398            self.process_transaction(&[ix], &signer.pubkey(), &[signer])
399                .await?;
400        }
401
402        if !self.print_tx {
403            let account = self
404                .get_account::<jito_restaking_client::accounts::Ncn>(&ncn)
405                .await?;
406            info!("{}", account.pretty_display());
407        }
408
409        Ok(())
410    }
411
412    /// Sets the primary admin for an Operator
413    ///
414    /// This function transfers administrative control of an Operator account from the current admin
415    /// to a new admin. It supports both file-based keypairs and hardware wallets (USB devices)
416    /// for both the old and new admin. The function first converts the operator string to a public key,
417    /// resolves the signers, then builds and processes a transaction that updates the admin public key
418    /// in the Operator account.
419    #[allow(clippy::future_not_send)]
420    async fn operator_set_admin(
421        &self,
422        operator: &str,
423        old_admin_keypair: &str,
424        new_admin_keypair: &str,
425    ) -> Result<()> {
426        let operator = Pubkey::from_str(operator)?;
427
428        let mut old_admin_owned = None;
429        let mut new_admin_owned = None;
430
431        let old_admin_signer = self.resolve_keypair(old_admin_keypair, &mut old_admin_owned)?;
432        let new_admin_signer = self.resolve_keypair(new_admin_keypair, &mut new_admin_owned)?;
433
434        let mut ix_builder = OperatorSetAdminBuilder::new();
435        ix_builder
436            .operator(operator)
437            .old_admin(old_admin_signer.pubkey())
438            .new_admin(new_admin_signer.pubkey());
439        let mut ix = ix_builder.instruction();
440        ix.program_id = self.restaking_program_id;
441
442        info!("Setting Operator admin to {}", new_admin_signer.pubkey());
443
444        self.process_transaction(
445            &[ix],
446            &new_admin_signer.pubkey(),
447            &[new_admin_signer, old_admin_signer],
448        )
449        .await?;
450
451        if !self.print_tx {
452            let account = self
453                .get_account::<jito_restaking_client::accounts::Operator>(&operator)
454                .await?;
455            info!("{}", account.pretty_display());
456        }
457
458        Ok(())
459    }
460
461    #[allow(clippy::future_not_send)]
462    pub async fn operator_set_fee(&self, operator: String, operator_fee_bps: u16) -> Result<()> {
463        let signer = self
464            .cli_config
465            .signer
466            .as_ref()
467            .ok_or_else(|| anyhow!("No signer"))?;
468
469        let (restaking_vault_config, _, _) =
470            Config::find_program_address(&self.restaking_program_id);
471
472        let operator = Pubkey::from_str(&operator)?;
473
474        let mut ix_builder = OperatorSetFeeBuilder::new();
475        ix_builder
476            .operator(operator)
477            .new_fee_bps(operator_fee_bps)
478            .admin(signer.pubkey())
479            .config(restaking_vault_config)
480            .instruction();
481        let mut ix = ix_builder.instruction();
482        ix.program_id = self.restaking_program_id;
483
484        info!(
485            "Setting fees to {:?} to Operator {}",
486            operator_fee_bps, operator,
487        );
488
489        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
490            .await?;
491
492        if !self.print_tx {
493            let account = self
494                .get_account::<jito_restaking_client::accounts::Operator>(&operator)
495                .await?;
496            info!("{}", account.pretty_display());
497        }
498
499        Ok(())
500    }
501
502    #[allow(clippy::too_many_arguments, clippy::future_not_send)]
503    pub async fn operator_set_secondary_admin(
504        &self,
505        operator: String,
506        new_admin: String,
507        set_ncn_admin: bool,
508        set_vault_admin: bool,
509        set_voter_admin: bool,
510        set_delegate_admin: bool,
511        set_metadata_admin: bool,
512    ) -> Result<()> {
513        let signer = self
514            .cli_config
515            .signer
516            .as_ref()
517            .ok_or_else(|| anyhow!("No signer"))?;
518
519        let operator = Pubkey::from_str(&operator)?;
520        let new_admin = Pubkey::from_str(&new_admin)?;
521
522        let mut roles: Vec<OperatorAdminRole> = vec![];
523        if set_ncn_admin {
524            roles.push(OperatorAdminRole::NcnAdmin);
525        }
526        if set_vault_admin {
527            roles.push(OperatorAdminRole::VaultAdmin);
528        }
529        if set_voter_admin {
530            roles.push(OperatorAdminRole::VoterAdmin);
531        }
532        if set_delegate_admin {
533            roles.push(OperatorAdminRole::DelegateAdmin);
534        }
535        if set_metadata_admin {
536            roles.push(OperatorAdminRole::MetadataAdmin);
537        }
538
539        for role in roles.iter() {
540            let mut ix_builder = OperatorSetSecondaryAdminBuilder::new();
541            ix_builder
542                .new_admin(new_admin)
543                .operator(operator)
544                .admin(signer.pubkey())
545                .operator_admin_role(*role)
546                .instruction();
547            let mut ix = ix_builder.instruction();
548            ix.program_id = self.restaking_program_id;
549
550            info!(
551                "Setting {:?} Admin to {} for Operator {}",
552                role, new_admin, operator
553            );
554
555            self.process_transaction(&[ix], &signer.pubkey(), &[signer])
556                .await?;
557        }
558
559        if !self.print_tx {
560            let account = self
561                .get_account::<jito_restaking_client::accounts::Operator>(&operator)
562                .await?;
563            info!("{}", account.pretty_display());
564        }
565
566        Ok(())
567    }
568
569    #[allow(clippy::future_not_send)]
570    pub async fn operator_delegate_token_account(
571        &self,
572        operator: String,
573        delegate: String,
574        token_mint: String,
575        should_create_token_account: bool,
576    ) -> Result<()> {
577        let signer = self
578            .cli_config
579            .signer
580            .as_ref()
581            .ok_or_else(|| anyhow!("No signer"))?;
582
583        let operator = Pubkey::from_str(&operator)?;
584        let delegate = Pubkey::from_str(&delegate)?;
585        let token_mint = Pubkey::from_str(&token_mint)?;
586
587        let token_account = get_associated_token_address(&operator, &token_mint);
588
589        let mut ixs = vec![];
590
591        if should_create_token_account {
592            let ix = create_associated_token_account_idempotent(
593                &signer.pubkey(),
594                &operator,
595                &token_mint,
596                &spl_token::id(),
597            );
598            ixs.push(ix);
599        }
600
601        let mut ix_builder = OperatorDelegateTokenAccountBuilder::new();
602        ix_builder
603            .operator(operator)
604            .delegate(delegate)
605            .delegate_admin(signer.pubkey())
606            .token_account(token_account)
607            .token_mint(token_mint);
608        let mut ix = ix_builder.instruction();
609        ix.program_id = self.restaking_program_id;
610
611        ixs.push(ix_builder.instruction());
612
613        info!("Setting delegate for mint: {} to {}", token_mint, delegate,);
614
615        self.process_transaction(&ixs, &signer.pubkey(), &[signer])
616            .await?;
617
618        Ok(())
619    }
620
621    #[allow(clippy::future_not_send)]
622    pub async fn ncn_delegate_token_account(
623        &self,
624        ncn: String,
625        delegate: String,
626        token_mint: String,
627        should_create_token_account: bool,
628    ) -> Result<()> {
629        let signer = self
630            .cli_config
631            .signer
632            .as_ref()
633            .ok_or_else(|| anyhow!("No signer"))?;
634
635        let ncn = Pubkey::from_str(&ncn)?;
636        let delegate = Pubkey::from_str(&delegate)?;
637        let token_mint = Pubkey::from_str(&token_mint)?;
638
639        let token_account = get_associated_token_address(&ncn, &token_mint);
640
641        let mut ixs = vec![];
642
643        if should_create_token_account {
644            let ix = create_associated_token_account_idempotent(
645                &signer.pubkey(),
646                &ncn,
647                &token_mint,
648                &spl_token::id(),
649            );
650            ixs.push(ix);
651        }
652
653        let mut ix_builder = NcnDelegateTokenAccountBuilder::new();
654        ix_builder
655            .ncn(ncn)
656            .delegate(delegate)
657            .delegate_admin(signer.pubkey())
658            .token_account(token_account)
659            .token_mint(token_mint);
660        let mut ix = ix_builder.instruction();
661        ix.program_id = self.restaking_program_id;
662
663        ixs.push(ix_builder.instruction());
664
665        info!("Setting delegate for mint: {} to {}", token_mint, delegate,);
666
667        self.process_transaction(&ixs, &signer.pubkey(), &[signer])
668            .await?;
669
670        Ok(())
671    }
672
673    #[allow(clippy::future_not_send)]
674    pub async fn initialize_ncn_vault_ticket(&self, ncn: String, vault: String) -> Result<()> {
675        let signer = self
676            .cli_config
677            .signer
678            .as_ref()
679            .ok_or_else(|| anyhow!("No signer"))?;
680
681        let ncn = Pubkey::from_str(&ncn)?;
682        let vault = Pubkey::from_str(&vault)?;
683
684        let (ncn_vault_ticket, _, _) =
685            NcnVaultTicket::find_program_address(&self.restaking_program_id, &ncn, &vault);
686
687        let mut ix_builder = InitializeNcnVaultTicketBuilder::new();
688        ix_builder
689            .config(Config::find_program_address(&self.restaking_program_id).0)
690            .ncn(ncn)
691            .vault(vault)
692            .ncn_vault_ticket(ncn_vault_ticket)
693            .admin(signer.pubkey())
694            .payer(signer.pubkey())
695            .instruction();
696        let mut ix = ix_builder.instruction();
697        ix.program_id = self.restaking_program_id;
698
699        info!("Initializing NCN Vault Ticket");
700
701        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
702            .await?;
703
704        if !self.print_tx {
705            let account = self
706                .get_account::<jito_restaking_client::accounts::NcnVaultTicket>(&ncn_vault_ticket)
707                .await?;
708            info!("{}", account.pretty_display());
709        }
710
711        Ok(())
712    }
713
714    #[allow(clippy::future_not_send)]
715    pub async fn warmup_ncn_vault_ticket(&self, ncn: String, vault: String) -> Result<()> {
716        let signer = self
717            .cli_config
718            .signer
719            .as_ref()
720            .ok_or_else(|| anyhow!("No signer"))?;
721
722        let ncn = Pubkey::from_str(&ncn)?;
723        let vault = Pubkey::from_str(&vault)?;
724
725        let (ncn_vault_ticket, _, _) =
726            NcnVaultTicket::find_program_address(&self.restaking_program_id, &ncn, &vault);
727
728        let mut ix_builder = WarmupNcnVaultTicketBuilder::new();
729        ix_builder
730            .config(Config::find_program_address(&self.restaking_program_id).0)
731            .ncn(ncn)
732            .vault(vault)
733            .ncn_vault_ticket(ncn_vault_ticket)
734            .admin(signer.pubkey())
735            .instruction();
736        let mut ix = ix_builder.instruction();
737        ix.program_id = self.restaking_program_id;
738
739        info!("Warmup NCN Vault Ticket");
740
741        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
742            .await?;
743
744        if !self.print_tx {
745            let account = self
746                .get_account::<jito_restaking_client::accounts::NcnVaultTicket>(&ncn_vault_ticket)
747                .await?;
748            info!("{}", account.pretty_display());
749        }
750
751        Ok(())
752    }
753
754    #[allow(clippy::future_not_send)]
755    pub async fn cooldown_ncn_vault_ticket(&self, ncn: String, vault: String) -> Result<()> {
756        let signer = self
757            .cli_config
758            .signer
759            .as_ref()
760            .ok_or_else(|| anyhow!("No signer"))?;
761
762        let ncn = Pubkey::from_str(&ncn)?;
763        let vault = Pubkey::from_str(&vault)?;
764
765        let (ncn_vault_ticket, _, _) =
766            NcnVaultTicket::find_program_address(&self.restaking_program_id, &ncn, &vault);
767
768        let mut ix_builder = CooldownNcnVaultTicketBuilder::new();
769        ix_builder
770            .config(Config::find_program_address(&self.restaking_program_id).0)
771            .ncn(ncn)
772            .vault(vault)
773            .ncn_vault_ticket(ncn_vault_ticket)
774            .admin(signer.pubkey())
775            .instruction();
776        let mut ix = ix_builder.instruction();
777        ix.program_id = self.restaking_program_id;
778
779        info!("Cooldown NCN Vault Ticket");
780
781        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
782            .await?;
783
784        Ok(())
785    }
786
787    #[allow(clippy::future_not_send)]
788    pub async fn initialize_ncn_operator_state(&self, ncn: String, operator: String) -> Result<()> {
789        let signer = self
790            .cli_config
791            .signer
792            .as_ref()
793            .ok_or_else(|| anyhow!("No signer"))?;
794
795        let ncn = Pubkey::from_str(&ncn)?;
796        let operator = Pubkey::from_str(&operator)?;
797
798        let (ncn_operator_state, _, _) =
799            NcnOperatorState::find_program_address(&self.restaking_program_id, &ncn, &operator);
800
801        let mut ix_builder = InitializeNcnOperatorStateBuilder::new();
802        ix_builder
803            .config(Config::find_program_address(&self.restaking_program_id).0)
804            .ncn(ncn)
805            .operator(operator)
806            .ncn_operator_state(ncn_operator_state)
807            .admin(signer.pubkey())
808            .payer(signer.pubkey())
809            .instruction();
810        let mut ix = ix_builder.instruction();
811        ix.program_id = self.restaking_program_id;
812
813        info!("Initializing NCN Operator State");
814
815        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
816            .await?;
817
818        if !self.print_tx {
819            let account = self
820                .get_account::<jito_restaking_client::accounts::NcnOperatorState>(
821                    &ncn_operator_state,
822                )
823                .await?;
824            info!("{}", account.pretty_display());
825        }
826
827        Ok(())
828    }
829
830    #[allow(clippy::future_not_send)]
831    pub async fn ncn_warmup_operator(&self, ncn: String, operator: String) -> Result<()> {
832        let signer = self
833            .cli_config
834            .signer
835            .as_ref()
836            .ok_or_else(|| anyhow!("No signer"))?;
837
838        let ncn = Pubkey::from_str(&ncn)?;
839        let operator = Pubkey::from_str(&operator)?;
840
841        let (ncn_operator_state, _, _) =
842            NcnOperatorState::find_program_address(&self.restaking_program_id, &ncn, &operator);
843
844        let mut ix_builder = NcnWarmupOperatorBuilder::new();
845        ix_builder
846            .config(Config::find_program_address(&self.restaking_program_id).0)
847            .ncn(ncn)
848            .operator(operator)
849            .ncn_operator_state(ncn_operator_state)
850            .admin(signer.pubkey())
851            .instruction();
852        let mut ix = ix_builder.instruction();
853        ix.program_id = self.restaking_program_id;
854
855        info!("NCN Warmup Operator");
856
857        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
858            .await?;
859
860        if !self.print_tx {
861            let account = self
862                .get_account::<jito_restaking_client::accounts::NcnOperatorState>(
863                    &ncn_operator_state,
864                )
865                .await?;
866            info!("{}", account.pretty_display());
867        }
868
869        Ok(())
870    }
871
872    #[allow(clippy::future_not_send)]
873    pub async fn ncn_cooldown_operator(&self, ncn: String, operator: String) -> Result<()> {
874        let signer = self
875            .cli_config
876            .signer
877            .as_ref()
878            .ok_or_else(|| anyhow!("No signer"))?;
879
880        let ncn = Pubkey::from_str(&ncn)?;
881        let operator = Pubkey::from_str(&operator)?;
882
883        let (ncn_operator_state, _, _) =
884            NcnOperatorState::find_program_address(&self.restaking_program_id, &ncn, &operator);
885
886        let mut ix_builder = NcnCooldownOperatorBuilder::new();
887        ix_builder
888            .config(Config::find_program_address(&self.restaking_program_id).0)
889            .ncn(ncn)
890            .operator(operator)
891            .ncn_operator_state(ncn_operator_state)
892            .admin(signer.pubkey())
893            .instruction();
894        let mut ix = ix_builder.instruction();
895        ix.program_id = self.restaking_program_id;
896
897        info!("NCN Cooldown Operator");
898
899        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
900            .await?;
901
902        if !self.print_tx {
903            let account = self
904                .get_account::<jito_restaking_client::accounts::NcnOperatorState>(
905                    &ncn_operator_state,
906                )
907                .await?;
908            info!("{}", account.pretty_display());
909        }
910
911        Ok(())
912    }
913
914    #[allow(clippy::future_not_send)]
915    pub async fn operator_warmup_ncn(&self, operator: String, ncn: String) -> Result<()> {
916        let signer = self
917            .cli_config
918            .signer
919            .as_ref()
920            .ok_or_else(|| anyhow!("No signer"))?;
921
922        let operator = Pubkey::from_str(&operator)?;
923        let ncn = Pubkey::from_str(&ncn)?;
924
925        let (ncn_operator_state, _, _) =
926            NcnOperatorState::find_program_address(&self.restaking_program_id, &ncn, &operator);
927
928        let mut ix_builder = OperatorWarmupNcnBuilder::new();
929        ix_builder
930            .config(Config::find_program_address(&self.restaking_program_id).0)
931            .ncn(ncn)
932            .operator(operator)
933            .ncn_operator_state(ncn_operator_state)
934            .admin(signer.pubkey())
935            .instruction();
936        let mut ix = ix_builder.instruction();
937        ix.program_id = self.restaking_program_id;
938
939        info!("Operator Warmup NCN");
940
941        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
942            .await?;
943
944        if !self.print_tx {
945            let account = self
946                .get_account::<jito_restaking_client::accounts::NcnOperatorState>(
947                    &ncn_operator_state,
948                )
949                .await?;
950            info!("{}", account.pretty_display());
951        }
952
953        Ok(())
954    }
955
956    #[allow(clippy::future_not_send)]
957    pub async fn operator_cooldown_ncn(&self, operator: String, ncn: String) -> Result<()> {
958        let signer = self
959            .cli_config
960            .signer
961            .as_ref()
962            .ok_or_else(|| anyhow!("No signer"))?;
963
964        let operator = Pubkey::from_str(&operator)?;
965        let ncn = Pubkey::from_str(&ncn)?;
966
967        let (ncn_operator_state, _, _) =
968            NcnOperatorState::find_program_address(&self.restaking_program_id, &ncn, &operator);
969
970        let mut ix_builder = OperatorCooldownNcnBuilder::new();
971        ix_builder
972            .config(Config::find_program_address(&self.restaking_program_id).0)
973            .ncn(ncn)
974            .operator(operator)
975            .ncn_operator_state(ncn_operator_state)
976            .admin(signer.pubkey())
977            .instruction();
978        let mut ix = ix_builder.instruction();
979        ix.program_id = self.restaking_program_id;
980
981        info!("Operator Cooldown NCN");
982
983        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
984            .await?;
985
986        if !self.print_tx {
987            let account = self
988                .get_account::<jito_restaking_client::accounts::NcnOperatorState>(
989                    &ncn_operator_state,
990                )
991                .await?;
992            info!("{}", account.pretty_display());
993        }
994
995        Ok(())
996    }
997
998    #[allow(clippy::future_not_send)]
999    async fn initialize_config(&self) -> Result<()> {
1000        let signer = self
1001            .cli_config
1002            .signer
1003            .as_ref()
1004            .ok_or_else(|| anyhow!("No signer"))?;
1005
1006        let config_address = Config::find_program_address(&self.restaking_program_id).0;
1007        let mut ix_builder = InitializeConfigBuilder::new();
1008        ix_builder
1009            .config(config_address)
1010            .admin(signer.pubkey())
1011            .vault_program(self.vault_program_id);
1012        let mut ix = ix_builder.instruction();
1013        ix.program_id = self.restaking_program_id;
1014
1015        info!("Initializing restaking config parameters: {:?}", ix_builder);
1016
1017        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
1018            .await?;
1019
1020        if !self.print_tx {
1021            let account = self
1022                .get_account::<jito_restaking_client::accounts::Config>(&config_address)
1023                .await?;
1024            info!("{}", account.pretty_display());
1025        }
1026
1027        Ok(())
1028    }
1029
1030    #[allow(clippy::future_not_send)]
1031    pub async fn initialize_ncn(&self, path_to_base_keypair: Option<String>) -> Result<()> {
1032        let signer = self
1033            .cli_config
1034            .signer
1035            .as_ref()
1036            .ok_or_else(|| anyhow!("No signer"))?;
1037
1038        let base =
1039            path_to_base_keypair.map_or_else(Keypair::new, |path| read_keypair_file(path).unwrap());
1040        let base_signer = CliSigner::new(Some(base), None);
1041        let ncn = Ncn::find_program_address(&self.restaking_program_id, &base_signer.pubkey()).0;
1042
1043        let mut ix_builder = InitializeNcnBuilder::new();
1044        ix_builder
1045            .config(Config::find_program_address(&self.restaking_program_id).0)
1046            .ncn(ncn)
1047            .admin(signer.pubkey())
1048            .base(base_signer.pubkey())
1049            .instruction();
1050        let mut ix = ix_builder.instruction();
1051        ix.program_id = self.restaking_program_id;
1052
1053        info!("Initializing NCN: {:?}", ncn);
1054
1055        self.process_transaction(&[ix], &signer.pubkey(), &[signer, &base_signer])
1056            .await?;
1057
1058        if !self.print_tx {
1059            let account = self
1060                .get_account::<jito_restaking_client::accounts::Ncn>(&ncn)
1061                .await?;
1062            info!("{}", account.pretty_display());
1063        }
1064
1065        Ok(())
1066    }
1067
1068    #[allow(clippy::future_not_send)]
1069    pub async fn initialize_operator(&self, operator_fee_bps: u16) -> Result<()> {
1070        let signer = self
1071            .cli_config
1072            .signer
1073            .as_ref()
1074            .ok_or_else(|| anyhow!("No signer"))?;
1075
1076        let base_signer = CliSigner::new(Some(Keypair::new()), None);
1077        let operator =
1078            Operator::find_program_address(&self.restaking_program_id, &base_signer.pubkey()).0;
1079
1080        let mut ix_builder = InitializeOperatorBuilder::new();
1081        ix_builder
1082            .config(Config::find_program_address(&self.restaking_program_id).0)
1083            .operator(operator)
1084            .admin(signer.pubkey())
1085            .base(base_signer.pubkey())
1086            .operator_fee_bps(operator_fee_bps)
1087            .instruction();
1088        let mut ix = ix_builder.instruction();
1089        ix.program_id = self.restaking_program_id;
1090
1091        info!("Initializing Operator: {:?}", operator);
1092
1093        self.process_transaction(&[ix], &signer.pubkey(), &[signer, &base_signer])
1094            .await?;
1095
1096        if !self.print_tx {
1097            let account = self
1098                .get_account::<jito_restaking_client::accounts::Operator>(&operator)
1099                .await?;
1100            info!("{}", account.pretty_display());
1101        }
1102
1103        Ok(())
1104    }
1105
1106    #[allow(clippy::future_not_send)]
1107    pub async fn initialize_operator_vault_ticket(
1108        &self,
1109        operator: String,
1110        vault: String,
1111    ) -> Result<()> {
1112        let signer = self
1113            .cli_config
1114            .signer
1115            .as_ref()
1116            .ok_or_else(|| anyhow!("Keypair not provided"))?;
1117
1118        let operator = Pubkey::from_str(&operator)?;
1119        let vault = Pubkey::from_str(&vault)?;
1120
1121        let operator_vault_ticket = OperatorVaultTicket::find_program_address(
1122            &self.restaking_program_id,
1123            &operator,
1124            &vault,
1125        )
1126        .0;
1127
1128        let mut ix_builder = InitializeOperatorVaultTicketBuilder::new();
1129        ix_builder
1130            .config(Config::find_program_address(&self.restaking_program_id).0)
1131            .operator(operator)
1132            .vault(vault)
1133            .admin(signer.pubkey())
1134            .operator_vault_ticket(operator_vault_ticket)
1135            .payer(signer.pubkey());
1136        let mut ix = ix_builder.instruction();
1137        ix.program_id = self.restaking_program_id;
1138
1139        info!("Operator Vault Ticket address: {}", operator_vault_ticket);
1140        info!("Operator address: {}", operator);
1141        info!("Vault address: {}", vault);
1142
1143        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
1144            .await?;
1145
1146        if !self.print_tx {
1147            let account = self
1148                .get_account::<jito_restaking_client::accounts::OperatorVaultTicket>(
1149                    &operator_vault_ticket,
1150                )
1151                .await?;
1152            info!("{}", account.pretty_display());
1153        }
1154
1155        Ok(())
1156    }
1157
1158    #[allow(clippy::future_not_send)]
1159    pub async fn warmup_operator_vault_ticket(
1160        &self,
1161        operator: String,
1162        vault: String,
1163    ) -> Result<()> {
1164        let signer = self
1165            .cli_config
1166            .signer
1167            .as_ref()
1168            .ok_or_else(|| anyhow!("Keypair not provided"))?;
1169
1170        let operator = Pubkey::from_str(&operator)?;
1171        let vault = Pubkey::from_str(&vault)?;
1172
1173        let operator_vault_ticket = OperatorVaultTicket::find_program_address(
1174            &self.restaking_program_id,
1175            &operator,
1176            &vault,
1177        )
1178        .0;
1179
1180        let mut ix_builder = WarmupOperatorVaultTicketBuilder::new();
1181        ix_builder
1182            .config(Config::find_program_address(&self.restaking_program_id).0)
1183            .operator(operator)
1184            .vault(vault)
1185            .operator_vault_ticket(operator_vault_ticket)
1186            .admin(signer.pubkey());
1187        let mut ix = ix_builder.instruction();
1188        ix.program_id = self.restaking_program_id;
1189
1190        info!("Warming up operator vault ticket transaction");
1191        info!("Operator address: {}", operator);
1192        info!("Vault address: {}", vault);
1193
1194        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
1195            .await?;
1196
1197        if !self.print_tx {
1198            let account = self
1199                .get_account::<jito_restaking_client::accounts::OperatorVaultTicket>(
1200                    &operator_vault_ticket,
1201                )
1202                .await?;
1203            info!("{}", account.pretty_display());
1204        }
1205
1206        Ok(())
1207    }
1208
1209    #[allow(clippy::future_not_send)]
1210    pub async fn cooldown_operator_vault_ticket(
1211        &self,
1212        operator: String,
1213        vault: String,
1214    ) -> Result<()> {
1215        let signer = self
1216            .cli_config
1217            .signer
1218            .as_ref()
1219            .ok_or_else(|| anyhow!("Keypair not provided"))?;
1220
1221        let operator = Pubkey::from_str(&operator)?;
1222        let vault = Pubkey::from_str(&vault)?;
1223
1224        let operator_vault_ticket = OperatorVaultTicket::find_program_address(
1225            &self.restaking_program_id,
1226            &operator,
1227            &vault,
1228        )
1229        .0;
1230
1231        let mut ix_builder = CooldownOperatorVaultTicketBuilder::new();
1232        ix_builder
1233            .config(Config::find_program_address(&self.restaking_program_id).0)
1234            .operator(operator)
1235            .vault(vault)
1236            .operator_vault_ticket(operator_vault_ticket)
1237            .admin(signer.pubkey());
1238        let mut ix = ix_builder.instruction();
1239        ix.program_id = self.restaking_program_id;
1240
1241        info!("Cooldown Operator Vault Ticket");
1242        info!("Operator address: {}", operator);
1243        info!("Vault address: {}", vault);
1244
1245        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
1246            .await?;
1247
1248        if !self.print_tx {
1249            let account = self
1250                .get_account::<jito_restaking_client::accounts::OperatorVaultTicket>(
1251                    &operator_vault_ticket,
1252                )
1253                .await?;
1254            info!("{}", account.pretty_display());
1255        }
1256
1257        Ok(())
1258    }
1259
1260    #[allow(clippy::future_not_send)]
1261    pub async fn get_config(&self) -> Result<()> {
1262        let rpc_client = self.get_rpc_client();
1263
1264        let config_address = Config::find_program_address(&self.restaking_program_id).0;
1265
1266        let account = rpc_client.get_account(&config_address).await?;
1267        let config =
1268            jito_restaking_client::accounts::Config::deserialize(&mut account.data.as_slice())?;
1269
1270        self.print_out(None, Some(&config_address), &config)?;
1271
1272        Ok(())
1273    }
1274
1275    #[allow(clippy::future_not_send)]
1276    pub async fn get_ncn(&self, pubkey: String) -> Result<()> {
1277        let pubkey = Pubkey::from_str(&pubkey)?;
1278        let account = self.get_rpc_client().get_account(&pubkey).await?;
1279        let ncn = jito_restaking_client::accounts::Ncn::deserialize(&mut account.data.as_slice())?;
1280
1281        self.print_out(None, Some(&pubkey), &ncn)?;
1282
1283        Ok(())
1284    }
1285
1286    #[allow(clippy::future_not_send)]
1287    pub async fn list_ncn(&self) -> Result<()> {
1288        let rpc_client = self.get_rpc_client();
1289        let config = self.get_rpc_program_accounts_config::<Ncn>(None)?;
1290
1291        let accounts = rpc_client
1292            .get_program_accounts_with_config(&self.restaking_program_id, config)
1293            .await?;
1294        for (index, (ncn_pubkey, ncn)) in accounts.iter().enumerate() {
1295            let ncn = jito_restaking_client::accounts::Ncn::deserialize(&mut ncn.data.as_slice())?;
1296
1297            self.print_out(Some(index), Some(ncn_pubkey), &ncn)?;
1298        }
1299        Ok(())
1300    }
1301
1302    /// Lists NCN operator state accounts filtered by either NCN or Operator public key.
1303    #[allow(clippy::future_not_send)]
1304    pub async fn list_ncn_operator_state(
1305        &self,
1306        ncn: Option<&Pubkey>,
1307        operator: Option<&Pubkey>,
1308    ) -> Result<()> {
1309        let rpc_client = self.get_rpc_client();
1310
1311        let (pubkey, offset) = match (ncn, operator) {
1312            (Some(ncn_pubkey), None) => (ncn_pubkey, 8),
1313            (None, Some(operator_pubkey)) => (operator_pubkey, 8 + 32),
1314            _ => return Err(anyhow!("Choose Operator or NCN")),
1315        };
1316
1317        let config =
1318            self.get_rpc_program_accounts_config::<NcnOperatorState>(Some((pubkey, offset)))?;
1319
1320        let accounts = rpc_client
1321            .get_program_accounts_with_config(&self.restaking_program_id, config)
1322            .await?;
1323        for (index, (ncn_operator_state_pubkey, ncn_operator_state)) in accounts.iter().enumerate()
1324        {
1325            let ncn_operator_state =
1326                jito_restaking_client::accounts::NcnOperatorState::deserialize(
1327                    &mut ncn_operator_state.data.as_slice(),
1328                )?;
1329            self.print_out(
1330                Some(index),
1331                Some(ncn_operator_state_pubkey),
1332                &ncn_operator_state,
1333            )?;
1334        }
1335        Ok(())
1336    }
1337
1338    /// Lists NCN operator state accounts filtered by NCN public key.
1339    #[allow(clippy::future_not_send)]
1340    pub async fn list_ncn_vault_ticket(&self, ncn: Pubkey) -> Result<()> {
1341        let rpc_client = self.get_rpc_client();
1342        let config = self.get_rpc_program_accounts_config::<NcnVaultTicket>(Some((&ncn, 8)))?;
1343
1344        let accounts = rpc_client
1345            .get_program_accounts_with_config(&self.restaking_program_id, config)
1346            .await?;
1347        for (index, (ticket_pubkey, ticket)) in accounts.iter().enumerate() {
1348            let ticket = jito_restaking_client::accounts::NcnVaultTicket::deserialize(
1349                &mut ticket.data.as_slice(),
1350            )?;
1351            self.print_out(Some(index), Some(ticket_pubkey), &ticket)?;
1352        }
1353        Ok(())
1354    }
1355
1356    #[allow(clippy::future_not_send)]
1357    pub async fn get_operator(&self, pubkey: String) -> Result<()> {
1358        let pubkey = Pubkey::from_str(&pubkey)?;
1359        let account = self.get_rpc_client().get_account(&pubkey).await?;
1360        let operator =
1361            jito_restaking_client::accounts::Operator::deserialize(&mut account.data.as_slice())?;
1362        self.print_out(None, Some(&pubkey), &operator)?;
1363
1364        Ok(())
1365    }
1366
1367    #[allow(clippy::future_not_send)]
1368    pub async fn list_operator(&self) -> Result<()> {
1369        let rpc_client = self.get_rpc_client();
1370        let config = self.get_rpc_program_accounts_config::<Operator>(None)?;
1371        let accounts = rpc_client
1372            .get_program_accounts_with_config(&self.restaking_program_id, config)
1373            .await?;
1374        for (index, (operator_pubkey, operator)) in accounts.iter().enumerate() {
1375            let operator = jito_restaking_client::accounts::Operator::deserialize(
1376                &mut operator.data.as_slice(),
1377            )?;
1378            self.print_out(Some(index), Some(operator_pubkey), &operator)?;
1379        }
1380        Ok(())
1381    }
1382
1383    #[allow(clippy::future_not_send)]
1384    pub async fn list_operator_vault_ticket(&self, operator: &Pubkey) -> Result<()> {
1385        let rpc_client = self.get_rpc_client();
1386        let config =
1387            self.get_rpc_program_accounts_config::<OperatorVaultTicket>(Some((operator, 8)))?;
1388        let accounts = rpc_client
1389            .get_program_accounts_with_config(&self.restaking_program_id, config)
1390            .await?;
1391        for (index, (ticket_pubkey, ticket)) in accounts.iter().enumerate() {
1392            let ticket = jito_restaking_client::accounts::OperatorVaultTicket::deserialize(
1393                &mut ticket.data.as_slice(),
1394            )?;
1395            self.print_out(Some(index), Some(ticket_pubkey), &ticket)?;
1396        }
1397        Ok(())
1398    }
1399
1400    #[allow(clippy::future_not_send)]
1401    async fn set_config_admin(&self, new_admin: Pubkey) -> Result<()> {
1402        let signer = self
1403            .cli_config
1404            .signer
1405            .as_ref()
1406            .ok_or_else(|| anyhow!("No signer"))?;
1407
1408        let config_address = Config::find_program_address(&self.restaking_program_id).0;
1409        let mut ix_builder = SetConfigAdminBuilder::new();
1410        ix_builder
1411            .config(config_address)
1412            .old_admin(signer.pubkey())
1413            .new_admin(new_admin);
1414        let mut ix = ix_builder.instruction();
1415        ix.program_id = self.restaking_program_id;
1416
1417        info!(
1418            "Setting restaking config admin parameters: {:?}",
1419            ix_builder
1420        );
1421        self.process_transaction(&[ix], &signer.pubkey(), &[signer])
1422            .await?;
1423
1424        if !self.print_tx {
1425            let account = self
1426                .get_account::<jito_restaking_client::accounts::Config>(&config_address)
1427                .await?;
1428            info!("{}", account.pretty_display());
1429        }
1430
1431        Ok(())
1432    }
1433}