1
1
use clap:: {
2
2
crate_description, crate_name, crate_version, value_t, value_t_or_exit, App , AppSettings , Arg ,
3
- SubCommand ,
3
+ ArgGroup , SubCommand ,
4
4
} ;
5
5
use solana_account_decoder:: UiAccountEncoding ;
6
6
use solana_clap_utils:: {
@@ -25,8 +25,8 @@ use solana_sdk::{
25
25
} ;
26
26
use spl_stake_pool:: {
27
27
instruction:: {
28
- claim, deposit, initialize as initialize_pool, withdraw , Fee as PoolFee ,
29
- InitArgs as PoolInitArgs ,
28
+ claim, deposit, initialize as initialize_pool, set_owner , set_staking_authority , withdraw ,
29
+ Fee as PoolFee , InitArgs as PoolInitArgs ,
30
30
} ,
31
31
processor:: Processor as PoolProcessor ,
32
32
stake:: authorize as authorize_stake,
@@ -361,16 +361,16 @@ fn command_list(config: &Config, pool: &Pubkey) -> CommandResult {
361
361
let accounts = get_authority_accounts ( config, & pool_withdraw_authority) ;
362
362
363
363
if accounts. is_empty ( ) {
364
- println ! ( "No accounts found." )
365
- } else {
366
- let mut total_balance: u64 = 0 ;
367
- for ( pubkey, account) in accounts {
368
- let balance = account. lamports ;
369
- total_balance += balance;
370
- println ! ( "{}\t {} SOL" , pubkey, lamports_to_sol( balance) ) ;
371
- }
372
- println ! ( "Total: {} SOL" , lamports_to_sol( total_balance) ) ;
364
+ return Err ( "No accounts found." . to_string ( ) . into ( ) ) ;
365
+ }
366
+
367
+ let mut total_balance: u64 = 0 ;
368
+ for ( pubkey, account) in accounts {
369
+ let balance = account. lamports ;
370
+ total_balance += balance;
371
+ println ! ( "{}\t {} SOL" , pubkey, lamports_to_sol( balance) ) ;
373
372
}
373
+ println ! ( "Total: {} SOL" , lamports_to_sol( total_balance) ) ;
374
374
375
375
Ok ( None )
376
376
}
@@ -419,25 +419,23 @@ fn command_withdraw(
419
419
TokenAccount :: unpack_from_slice ( account_data. as_slice ( ) ) . unwrap ( ) ;
420
420
421
421
if account_data. mint != pool_data. pool_mint {
422
- println ! ( "Wrong token account." ) ;
423
- return Ok ( None ) ;
422
+ return Err ( "Wrong token account." . to_string ( ) . into ( ) ) ;
424
423
}
425
424
426
425
// Check burn_from balance
427
426
let max_withdraw_amount = pool_tokens_to_stake_amount ( & pool_data, account_data. amount ) ;
428
427
if max_withdraw_amount < amount {
429
- println ! (
428
+ return Err ( format ! (
430
429
"Not enough token balance to withdraw {} SOL.\n Maximum withdraw amount is {} SOL." ,
431
430
lamports_to_sol( amount) ,
432
431
lamports_to_sol( max_withdraw_amount)
433
- ) ;
434
- return Ok ( None ) ;
432
+ )
433
+ . into ( ) ) ;
435
434
}
436
435
437
436
let mut accounts = get_authority_accounts ( config, & pool_withdraw_authority) ;
438
437
if accounts. is_empty ( ) {
439
- println ! ( "No accounts found." ) ;
440
- return Ok ( None ) ;
438
+ return Err ( "No accounts found." . to_string ( ) . into ( ) ) ;
441
439
}
442
440
// Sort from lowest to highest balance
443
441
accounts. sort_by ( |a, b| a. 1 . lamports . cmp ( & b. 1 . lamports ) ) ;
@@ -555,11 +553,109 @@ fn command_withdraw(
555
553
return Ok ( Some ( transaction) ) ;
556
554
}
557
555
558
- println ! (
556
+ Err ( format ! (
559
557
"No stake accounts found in this pool with enough balance to withdraw {} SOL." ,
560
558
lamports_to_sol( amount)
559
+ )
560
+ . into ( ) )
561
+ }
562
+
563
+ fn command_set_staking_auth (
564
+ config : & Config ,
565
+ pool : & Pubkey ,
566
+ stake_account : & Pubkey ,
567
+ new_staker : & Pubkey ,
568
+ ) -> CommandResult {
569
+ let pool_data = config. rpc_client . get_account_data ( & pool) ?;
570
+ let pool_data: StakePool = PoolState :: deserialize ( pool_data. as_slice ( ) )
571
+ . unwrap ( )
572
+ . stake_pool ( )
573
+ . unwrap ( ) ;
574
+
575
+ let pool_withdraw_authority: Pubkey = PoolProcessor :: authority_id (
576
+ & spl_stake_pool:: id ( ) ,
577
+ pool,
578
+ PoolProcessor :: AUTHORITY_WITHDRAW ,
579
+ pool_data. withdraw_bump_seed ,
580
+ )
581
+ . unwrap ( ) ;
582
+
583
+ let mut transaction = Transaction :: new_with_payer (
584
+ & [ set_staking_authority (
585
+ & spl_stake_pool:: id ( ) ,
586
+ & pool,
587
+ & config. owner . pubkey ( ) ,
588
+ & pool_withdraw_authority,
589
+ & stake_account,
590
+ & new_staker,
591
+ & stake_program_id ( ) ,
592
+ ) ?] ,
593
+ Some ( & config. fee_payer . pubkey ( ) ) ,
561
594
) ;
562
- Ok ( None )
595
+
596
+ let ( recent_blockhash, fee_calculator) = config. rpc_client . get_recent_blockhash ( ) ?;
597
+ check_fee_payer_balance ( config, fee_calculator. calculate_fee ( & transaction. message ( ) ) ) ?;
598
+ let mut signers = vec ! [ config. fee_payer. as_ref( ) , config. owner. as_ref( ) ] ;
599
+ unique_signers ! ( signers) ;
600
+ transaction. sign ( & signers, recent_blockhash) ;
601
+ Ok ( Some ( transaction) )
602
+ }
603
+
604
+ fn command_set_owner (
605
+ config : & Config ,
606
+ pool : & Pubkey ,
607
+ new_owner : & Option < Pubkey > ,
608
+ new_fee_receiver : & Option < Pubkey > ,
609
+ ) -> CommandResult {
610
+ let pool_data = config. rpc_client . get_account_data ( & pool) ?;
611
+ let pool_data: StakePool = PoolState :: deserialize ( pool_data. as_slice ( ) )
612
+ . unwrap ( )
613
+ . stake_pool ( )
614
+ . unwrap ( ) ;
615
+
616
+ // If new accounts are missing in the arguments use the old ones
617
+ let new_owner: Pubkey = match new_owner {
618
+ None => pool_data. owner ,
619
+ Some ( value) => * value,
620
+ } ;
621
+ let new_fee_receiver: Pubkey = match new_fee_receiver {
622
+ None => pool_data. owner_fee_account ,
623
+ Some ( value) => {
624
+ // Check for fee receiver being a valid token account and have to same mint as the stake pool
625
+ let account_data = config. rpc_client . get_account_data ( value) ?;
626
+ let account_data: TokenAccount =
627
+ match TokenAccount :: unpack_from_slice ( account_data. as_slice ( ) ) {
628
+ Ok ( data) => data,
629
+ Err ( _) => {
630
+ return Err ( format ! ( "{} is not a token account" , value) . into ( ) ) ;
631
+ }
632
+ } ;
633
+ if account_data. mint != pool_data. pool_mint {
634
+ return Err ( "Fee receiver account belongs to a different mint"
635
+ . to_string ( )
636
+ . into ( ) ) ;
637
+ }
638
+ * value
639
+ }
640
+ } ;
641
+
642
+ let mut transaction = Transaction :: new_with_payer (
643
+ & [ set_owner (
644
+ & spl_stake_pool:: id ( ) ,
645
+ & pool,
646
+ & config. owner . pubkey ( ) ,
647
+ & new_owner,
648
+ & new_fee_receiver,
649
+ ) ?] ,
650
+ Some ( & config. fee_payer . pubkey ( ) ) ,
651
+ ) ;
652
+
653
+ let ( recent_blockhash, fee_calculator) = config. rpc_client . get_recent_blockhash ( ) ?;
654
+ check_fee_payer_balance ( config, fee_calculator. calculate_fee ( & transaction. message ( ) ) ) ?;
655
+ let mut signers = vec ! [ config. fee_payer. as_ref( ) , config. owner. as_ref( ) ] ;
656
+ unique_signers ! ( signers) ;
657
+ transaction. sign ( & signers, recent_blockhash) ;
658
+ Ok ( Some ( transaction) )
563
659
}
564
660
565
661
fn main ( ) {
@@ -719,6 +815,68 @@ fn main() {
719
815
. help ( "Stake account to receive SOL from the stake pool. Defaults to a new stake account." ) ,
720
816
)
721
817
)
818
+ . subcommand ( SubCommand :: with_name ( "set-staking-auth" ) . about ( "Changes staking authority of one of the accounts from the stake pool." )
819
+ . arg (
820
+ Arg :: with_name ( "pool" )
821
+ . long ( "pool" )
822
+ . validator ( is_pubkey)
823
+ . value_name ( "ADDRESS" )
824
+ . takes_value ( true )
825
+ . required ( true )
826
+ . help ( "Stake pool address." ) ,
827
+ )
828
+ . arg (
829
+ Arg :: with_name ( "stake_account" )
830
+ . long ( "stake-account" )
831
+ . validator ( is_pubkey)
832
+ . value_name ( "ADDRESS" )
833
+ . takes_value ( true )
834
+ . required ( true )
835
+ . help ( "Stake account address to change staking authority." ) ,
836
+ )
837
+ . arg (
838
+ Arg :: with_name ( "new_staker" )
839
+ . long ( "new-staker" )
840
+ . validator ( is_pubkey)
841
+ . value_name ( "ADDRESS" )
842
+ . takes_value ( true )
843
+ . required ( true )
844
+ . help ( "Public key of the new staker account." ) ,
845
+ )
846
+ )
847
+ . subcommand ( SubCommand :: with_name ( "set-owner" ) . about ( "Changes owner or fee receiver account for the stake pool." )
848
+ . arg (
849
+ Arg :: with_name ( "pool" )
850
+ . long ( "pool" )
851
+ . validator ( is_pubkey)
852
+ . value_name ( "ADDRESS" )
853
+ . takes_value ( true )
854
+ . required ( true )
855
+ . help ( "Stake pool address." ) ,
856
+ )
857
+ . arg (
858
+ Arg :: with_name ( "new_owner" )
859
+ . long ( "new-owner" )
860
+ . validator ( is_pubkey)
861
+ . value_name ( "ADDRESS" )
862
+ . takes_value ( true )
863
+ . help ( "Public key for the new stake pool owner." ) ,
864
+ )
865
+ . arg (
866
+ Arg :: with_name ( "new_fee_receiver" )
867
+ . long ( "new-fee-receiver" )
868
+ . validator ( is_pubkey)
869
+ . value_name ( "ADDRESS" )
870
+ . takes_value ( true )
871
+ . help ( "Public key for the new account to set as the stake pool fee receiver." ) ,
872
+ )
873
+ . group ( ArgGroup :: with_name ( "new_accounts" )
874
+ . arg ( "new_owner" )
875
+ . arg ( "new_fee_receiver" )
876
+ . required ( true )
877
+ . multiple ( true )
878
+ )
879
+ )
722
880
. get_matches ( ) ;
723
881
724
882
let mut wallet_manager = None ;
@@ -793,6 +951,18 @@ fn main() {
793
951
let stake_receiver: Option < Pubkey > = pubkey_of ( arg_matches, "stake_receiver" ) ;
794
952
command_withdraw ( & config, & pool_account, amount, & burn_from, & stake_receiver)
795
953
}
954
+ ( "set-staking-auth" , Some ( arg_matches) ) => {
955
+ let pool_account: Pubkey = pubkey_of ( arg_matches, "pool" ) . unwrap ( ) ;
956
+ let stake_account: Pubkey = pubkey_of ( arg_matches, "stake_account" ) . unwrap ( ) ;
957
+ let new_staker: Pubkey = pubkey_of ( arg_matches, "new_staker" ) . unwrap ( ) ;
958
+ command_set_staking_auth ( & config, & pool_account, & stake_account, & new_staker)
959
+ }
960
+ ( "set-owner" , Some ( arg_matches) ) => {
961
+ let pool_account: Pubkey = pubkey_of ( arg_matches, "pool" ) . unwrap ( ) ;
962
+ let new_owner: Option < Pubkey > = pubkey_of ( arg_matches, "new_owner" ) ;
963
+ let new_fee_receiver: Option < Pubkey > = pubkey_of ( arg_matches, "new_fee_receiver" ) ;
964
+ command_set_owner ( & config, & pool_account, & new_owner, & new_fee_receiver)
965
+ }
796
966
_ => unreachable ! ( ) ,
797
967
}
798
968
. and_then ( |transaction| {
0 commit comments