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 cli_config: CliConfig,
41
42 restaking_program_id: Pubkey,
44
45 vault_program_id: Pubkey,
47
48 print_tx: bool,
50
51 print_json: bool,
53
54 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 #[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 #[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 #[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 #[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 #[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}