@@ -2716,15 +2716,14 @@ async fn process_account_sweep<T: Signers>(
2716
2716
db : & mut Db ,
2717
2717
rpc_client : & RpcClient ,
2718
2718
from_address : Pubkey ,
2719
+ token : MaybeToken ,
2719
2720
retain_amount : u64 ,
2720
2721
no_sweep_ok : bool ,
2721
2722
from_authority_address : Pubkey ,
2722
2723
signers : T ,
2723
2724
to_address : Option < Pubkey > ,
2724
2725
notifier : & Notifier ,
2725
2726
) -> Result < ( ) , Box < dyn std:: error:: Error > > {
2726
- let token = MaybeToken :: SOL ( ) ;
2727
-
2728
2727
let ( recent_blockhash, last_valid_block_height) =
2729
2728
rpc_client. get_latest_blockhash_with_commitment ( rpc_client. commitment ( ) ) ?;
2730
2729
let fee_calculator = get_deprecated_fee_calculator ( rpc_client) ?;
@@ -2738,16 +2737,6 @@ async fn process_account_sweep<T: Signers>(
2738
2737
. get_account ( from_address, token)
2739
2738
. ok_or_else ( || format ! ( "Account, {from_address}, is not tracked" ) ) ?;
2740
2739
2741
- if from_account. lamports < from_tracked_account. last_update_balance {
2742
- return Err ( format ! (
2743
- "{}: On-chain account balance ({}) less than tracked balance ({})" ,
2744
- from_address,
2745
- token. ui_amount( from_account. lamports) ,
2746
- token. ui_amount( from_tracked_account. last_update_balance)
2747
- )
2748
- . into ( ) ) ;
2749
- }
2750
-
2751
2740
let authority_account = if from_address == from_authority_address {
2752
2741
from_account. clone ( )
2753
2742
} else {
@@ -2765,6 +2754,10 @@ async fn process_account_sweep<T: Signers>(
2765
2754
. ok_or_else ( || format ! ( "Account {to_address} ({token}) does not exist" ) ) ?;
2766
2755
( to_address, None )
2767
2756
} else {
2757
+ if !token. is_sol ( ) {
2758
+ return Err ( "--to <ADDRESS> must be provided for token sweeps" . into ( ) ) ;
2759
+ }
2760
+
2768
2761
let transitory_stake_account = Keypair :: new ( ) ;
2769
2762
2770
2763
let sweep_stake_account = db
@@ -2804,60 +2797,94 @@ async fn process_account_sweep<T: Signers>(
2804
2797
. into ( ) ) ;
2805
2798
}
2806
2799
2807
- let ( mut instructions, sweep_amount) = if from_account. owner == system_program:: id ( ) {
2808
- let lamports = if from_address == from_authority_address {
2809
- from_tracked_account. last_update_balance . saturating_sub (
2810
- num_transaction_signatures * fee_calculator. lamports_per_signature + retain_amount,
2800
+ let ( mut instructions, sweep_amount) = if token. is_sol ( ) {
2801
+ if from_account. lamports < from_tracked_account. last_update_balance {
2802
+ return Err ( format ! (
2803
+ "{}: On-chain account balance ({}) less than tracked balance ({})" ,
2804
+ from_address,
2805
+ token. ui_amount( from_account. lamports) ,
2806
+ token. ui_amount( from_tracked_account. last_update_balance)
2811
2807
)
2812
- } else {
2813
- from_tracked_account
2814
- . last_update_balance
2815
- . saturating_sub ( retain_amount)
2816
- } ;
2808
+ . into ( ) ) ;
2809
+ }
2817
2810
2818
- (
2819
- vec ! [ system_instruction:: transfer(
2820
- & from_address,
2821
- & to_address,
2811
+ if from_account. owner == system_program:: id ( ) {
2812
+ let lamports = if from_address == from_authority_address {
2813
+ from_tracked_account. last_update_balance . saturating_sub (
2814
+ num_transaction_signatures * fee_calculator. lamports_per_signature
2815
+ + retain_amount,
2816
+ )
2817
+ } else {
2818
+ from_tracked_account
2819
+ . last_update_balance
2820
+ . saturating_sub ( retain_amount)
2821
+ } ;
2822
+
2823
+ (
2824
+ vec ! [ system_instruction:: transfer(
2825
+ & from_address,
2826
+ & to_address,
2827
+ lamports,
2828
+ ) ] ,
2822
2829
lamports,
2823
- ) ] ,
2824
- lamports,
2825
- )
2826
- } else if from_account. owner == solana_vote_program:: id ( ) {
2827
- let minimum_balance = rpc_client. get_minimum_balance_for_rent_exemption (
2828
- solana_vote_program:: vote_state:: VoteState :: size_of ( ) ,
2829
- ) ?;
2830
+ )
2831
+ } else if from_account. owner == solana_vote_program:: id ( ) {
2832
+ let minimum_balance = rpc_client. get_minimum_balance_for_rent_exemption (
2833
+ solana_vote_program:: vote_state:: VoteState :: size_of ( ) ,
2834
+ ) ?;
2830
2835
2831
- let lamports = from_tracked_account
2832
- . last_update_balance
2833
- . saturating_sub ( minimum_balance + retain_amount) ;
2836
+ let lamports = from_tracked_account
2837
+ . last_update_balance
2838
+ . saturating_sub ( minimum_balance + retain_amount) ;
2834
2839
2835
- (
2836
- vec ! [ solana_vote_program:: vote_instruction:: withdraw(
2837
- & from_address,
2838
- & from_authority_address,
2840
+ (
2841
+ vec ! [ solana_vote_program:: vote_instruction:: withdraw(
2842
+ & from_address,
2843
+ & from_authority_address,
2844
+ lamports,
2845
+ & to_address,
2846
+ ) ] ,
2839
2847
lamports,
2840
- & to_address,
2841
- ) ] ,
2842
- lamports,
2843
- )
2844
- } else if from_account. owner == solana_sdk:: stake:: program:: id ( ) {
2848
+ )
2849
+ } else if from_account. owner == solana_sdk:: stake:: program:: id ( ) {
2850
+ let lamports = from_tracked_account
2851
+ . last_update_balance
2852
+ . saturating_sub ( retain_amount) ;
2853
+
2854
+ (
2855
+ vec ! [ solana_sdk:: stake:: instruction:: withdraw(
2856
+ & from_address,
2857
+ & from_authority_address,
2858
+ & to_address,
2859
+ lamports,
2860
+ None ,
2861
+ ) ] ,
2862
+ lamports,
2863
+ )
2864
+ } else {
2865
+ return Err ( format ! ( "Unsupported `from` account owner: {}" , from_account. owner) . into ( ) ) ;
2866
+ }
2867
+ } else {
2868
+ let token = token. token ( ) . unwrap ( ) ;
2869
+
2845
2870
let lamports = from_tracked_account
2846
2871
. last_update_balance
2847
2872
. saturating_sub ( retain_amount) ;
2848
2873
2849
2874
(
2850
- vec ! [ solana_sdk:: stake:: instruction:: withdraw(
2851
- & from_address,
2875
+ vec ! [ spl_token:: instruction:: transfer_checked(
2876
+ & spl_token:: id( ) ,
2877
+ & token. ata( & from_address) ,
2878
+ & token. mint( ) ,
2879
+ & token. ata( & to_address) ,
2852
2880
& from_authority_address,
2853
- & to_address ,
2881
+ & [ ] ,
2854
2882
lamports,
2855
- None ,
2856
- ) ] ,
2883
+ token. decimals( ) ,
2884
+ )
2885
+ . unwrap( ) ] ,
2857
2886
lamports,
2858
2887
)
2859
- } else {
2860
- return Err ( format ! ( "Unsupported `from` account owner: {}" , from_account. owner) . into ( ) ) ;
2861
2888
} ;
2862
2889
2863
2890
if sweep_amount < token. amount ( 1. ) {
@@ -4286,6 +4313,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
4286
4313
. subcommand (
4287
4314
SubCommand :: with_name ( "sweep" )
4288
4315
. about ( "Sweep SOL into the sweep stake account" )
4316
+ . arg (
4317
+ Arg :: with_name ( "token" )
4318
+ . value_name ( "SOL or SPL Token" )
4319
+ . takes_value ( true )
4320
+ . required ( true )
4321
+ . validator ( is_valid_token_or_sol)
4322
+ . default_value ( "SOL" )
4323
+ . help ( "Token type" ) ,
4324
+ )
4289
4325
. arg (
4290
4326
Arg :: with_name ( "address" )
4291
4327
. value_name ( "ADDRESS" )
@@ -5698,6 +5734,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
5698
5734
. await ?;
5699
5735
}
5700
5736
( "sweep" , Some ( arg_matches) ) => {
5737
+ let token = value_t ! ( arg_matches, "token" , Token ) . ok ( ) ;
5701
5738
let from_address = pubkey_of ( arg_matches, "address" ) . unwrap ( ) ;
5702
5739
let ( from_authority_signer, from_authority_address) =
5703
5740
signer_of ( arg_matches, "authority" , & mut wallet_manager) ?;
@@ -5712,6 +5749,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
5712
5749
& mut db,
5713
5750
& rpc_client,
5714
5751
from_address,
5752
+ token. into ( ) ,
5715
5753
retain_amount,
5716
5754
no_sweep_ok,
5717
5755
from_authority_address,
0 commit comments