@@ -2,7 +2,11 @@ use clap::{
2
2
crate_description, crate_name, crate_version, value_t_or_exit, App , AppSettings , Arg ,
3
3
SubCommand ,
4
4
} ;
5
- use solana_account_decoder:: { parse_token:: TokenAccountType , UiAccountData } ;
5
+ use console:: Emoji ;
6
+ use solana_account_decoder:: {
7
+ parse_token:: { TokenAccountType , UiAccountState } ,
8
+ UiAccountData ,
9
+ } ;
6
10
use solana_clap_utils:: {
7
11
input_parsers:: pubkey_of,
8
12
input_validators:: { is_amount, is_keypair, is_pubkey_or_keypair, is_url} ,
@@ -26,6 +30,8 @@ use spl_token::{
26
30
} ;
27
31
use std:: process:: exit;
28
32
33
+ static WARNING : Emoji = Emoji ( "⚠️" , "!" ) ;
34
+
29
35
struct Config {
30
36
rpc_client : RpcClient ,
31
37
verbose : bool ,
@@ -74,12 +80,22 @@ fn check_owner_balance(config: &Config, required_balance: u64) -> Result<(), Err
74
80
}
75
81
}
76
82
77
- fn command_create_token ( config : & Config , decimals : u8 , token : Box < dyn Signer > ) -> CommandResult {
83
+ fn command_create_token (
84
+ config : & Config ,
85
+ decimals : u8 ,
86
+ token : Box < dyn Signer > ,
87
+ enable_freeze : bool ,
88
+ ) -> CommandResult {
78
89
println ! ( "Creating token {}" , token. pubkey( ) ) ;
79
90
80
91
let minimum_balance_for_rent_exemption = config
81
92
. rpc_client
82
93
. get_minimum_balance_for_rent_exemption ( Mint :: LEN ) ?;
94
+ let freeze_authority_pubkey = if enable_freeze {
95
+ Some ( config. owner . pubkey ( ) )
96
+ } else {
97
+ None
98
+ } ;
83
99
84
100
let mut transaction = Transaction :: new_with_payer (
85
101
& [
@@ -94,7 +110,7 @@ fn command_create_token(config: &Config, decimals: u8, token: Box<dyn Signer>) -
94
110
& spl_token:: id ( ) ,
95
111
& token. pubkey ( ) ,
96
112
& config. owner . pubkey ( ) ,
97
- None ,
113
+ freeze_authority_pubkey . as_ref ( ) ,
98
114
decimals,
99
115
) ?,
100
116
] ,
@@ -309,6 +325,50 @@ fn command_mint(
309
325
Ok ( Some ( transaction) )
310
326
}
311
327
328
+ fn command_freeze ( config : & Config , token : Pubkey , account : Pubkey ) -> CommandResult {
329
+ println ! ( "Freezing account: {}\n Token: {}" , account, token) ;
330
+
331
+ let mut transaction = Transaction :: new_with_payer (
332
+ & [ freeze_account (
333
+ & spl_token:: id ( ) ,
334
+ & account,
335
+ & token,
336
+ & config. owner . pubkey ( ) ,
337
+ & [ ] ,
338
+ ) ?] ,
339
+ Some ( & config. fee_payer . pubkey ( ) ) ,
340
+ ) ;
341
+
342
+ let ( recent_blockhash, fee_calculator) = config. rpc_client . get_recent_blockhash ( ) ?;
343
+ check_fee_payer_balance ( config, fee_calculator. calculate_fee ( & transaction. message ( ) ) ) ?;
344
+ let mut signers = vec ! [ config. fee_payer. as_ref( ) , config. owner. as_ref( ) ] ;
345
+ unique_signers ! ( signers) ;
346
+ transaction. sign ( & signers, recent_blockhash) ;
347
+ Ok ( Some ( transaction) )
348
+ }
349
+
350
+ fn command_thaw ( config : & Config , token : Pubkey , account : Pubkey ) -> CommandResult {
351
+ println ! ( "Freezing account: {}\n Token: {}" , account, token) ;
352
+
353
+ let mut transaction = Transaction :: new_with_payer (
354
+ & [ thaw_account (
355
+ & spl_token:: id ( ) ,
356
+ & account,
357
+ & token,
358
+ & config. owner . pubkey ( ) ,
359
+ & [ ] ,
360
+ ) ?] ,
361
+ Some ( & config. fee_payer . pubkey ( ) ) ,
362
+ ) ;
363
+
364
+ let ( recent_blockhash, fee_calculator) = config. rpc_client . get_recent_blockhash ( ) ?;
365
+ check_fee_payer_balance ( config, fee_calculator. calculate_fee ( & transaction. message ( ) ) ) ?;
366
+ let mut signers = vec ! [ config. fee_payer. as_ref( ) , config. owner. as_ref( ) ] ;
367
+ unique_signers ! ( signers) ;
368
+ transaction. sign ( & signers, recent_blockhash) ;
369
+ Ok ( Some ( transaction) )
370
+ }
371
+
312
372
fn command_wrap ( config : & Config , sol : f64 ) -> CommandResult {
313
373
let account = Keypair :: new ( ) ;
314
374
let lamports = sol_to_lamports ( sol) ;
@@ -429,10 +489,20 @@ fn command_accounts(config: &Config, token: Option<Pubkey>) -> CommandResult {
429
489
) ;
430
490
} else {
431
491
match serde_json:: from_value ( parsed_account. parsed ) {
432
- Ok ( TokenAccountType :: Account ( ui_token_account) ) => println ! (
433
- "{:<44} {:<44} {}" ,
434
- address, ui_token_account. mint, ui_token_account. token_amount. ui_amount
435
- ) ,
492
+ Ok ( TokenAccountType :: Account ( ui_token_account) ) => {
493
+ let maybe_frozen = if let UiAccountState :: Frozen = ui_token_account. state {
494
+ format ! ( " {} Frozen" , WARNING )
495
+ } else {
496
+ "" . to_string ( )
497
+ } ;
498
+ println ! (
499
+ "{:<44} {:<44} {}{}" ,
500
+ address,
501
+ ui_token_account. mint,
502
+ ui_token_account. token_amount. ui_amount,
503
+ maybe_frozen
504
+ )
505
+ }
436
506
Ok ( _) => println ! ( "{:<44} Unsupported token account" , address) ,
437
507
Err ( err) => println ! ( "{:<44} Account parse failure: {}" , address, err) ,
438
508
}
@@ -531,6 +601,14 @@ fn main() {
531
601
This may be a keypair file or the ASK keyword. \
532
602
[default: randomly generated keypair]"
533
603
) ,
604
+ )
605
+ . arg (
606
+ Arg :: with_name ( "enable_freeze" )
607
+ . long ( "enable-freeze" )
608
+ . takes_value ( false )
609
+ . help (
610
+ "Enable the mint authority to freeze associated token accounts."
611
+ ) ,
534
612
) ,
535
613
)
536
614
. subcommand (
@@ -664,6 +742,50 @@ fn main() {
664
742
. help ( "The token account address of recipient" ) ,
665
743
) ,
666
744
)
745
+ . subcommand (
746
+ SubCommand :: with_name ( "freeze" )
747
+ . about ( "Freeze a token account" )
748
+ . arg (
749
+ Arg :: with_name ( "token" ) // TODO: remove this arg when solana-client v1.3.12+ is published; grab mint from token account state
750
+ . validator ( is_pubkey_or_keypair)
751
+ . value_name ( "TOKEN_ADDRESS" )
752
+ . takes_value ( true )
753
+ . index ( 1 )
754
+ . required ( true )
755
+ . help ( "The token mint" ) ,
756
+ )
757
+ . arg (
758
+ Arg :: with_name ( "account" )
759
+ . validator ( is_pubkey_or_keypair)
760
+ . value_name ( "TOKEN_ACCOUNT_ADDRESS" )
761
+ . takes_value ( true )
762
+ . index ( 2 )
763
+ . required ( true )
764
+ . help ( "The address of the token account to freeze" ) ,
765
+ ) ,
766
+ )
767
+ . subcommand (
768
+ SubCommand :: with_name ( "thaw" )
769
+ . about ( "Thaw a token account" )
770
+ . arg (
771
+ Arg :: with_name ( "token" ) // TODO: remove this arg when solana-client v1.3.12+ is published; grab mint from token account state
772
+ . validator ( is_pubkey_or_keypair)
773
+ . value_name ( "TOKEN_ADDRESS" )
774
+ . takes_value ( true )
775
+ . index ( 1 )
776
+ . required ( true )
777
+ . help ( "The token mint" ) ,
778
+ )
779
+ . arg (
780
+ Arg :: with_name ( "account" )
781
+ . validator ( is_pubkey_or_keypair)
782
+ . value_name ( "TOKEN_ACCOUNT_ADDRESS" )
783
+ . takes_value ( true )
784
+ . index ( 2 )
785
+ . required ( true )
786
+ . help ( "The address of the token account to thaw" ) ,
787
+ ) ,
788
+ )
667
789
. subcommand (
668
790
SubCommand :: with_name ( "balance" )
669
791
. about ( "Get token account balance" )
@@ -798,7 +920,12 @@ fn main() {
798
920
Box :: new ( Keypair :: new ( ) )
799
921
} ;
800
922
801
- command_create_token ( & config, decimals, token)
923
+ command_create_token (
924
+ & config,
925
+ decimals,
926
+ token,
927
+ arg_matches. is_present ( "enable_freeze" ) ,
928
+ )
802
929
}
803
930
( "create-account" , Some ( arg_matches) ) => {
804
931
let token = pubkey_of ( arg_matches, "token" ) . unwrap ( ) ;
@@ -841,6 +968,16 @@ fn main() {
841
968
let recipient = pubkey_of ( arg_matches, "recipient" ) . unwrap ( ) ;
842
969
command_mint ( & config, token, amount, recipient)
843
970
}
971
+ ( "freeze" , Some ( arg_matches) ) => {
972
+ let token = pubkey_of ( arg_matches, "token" ) . unwrap ( ) ;
973
+ let account = pubkey_of ( arg_matches, "account" ) . unwrap ( ) ;
974
+ command_freeze ( & config, token, account)
975
+ }
976
+ ( "thaw" , Some ( arg_matches) ) => {
977
+ let token = pubkey_of ( arg_matches, "token" ) . unwrap ( ) ;
978
+ let account = pubkey_of ( arg_matches, "account" ) . unwrap ( ) ;
979
+ command_thaw ( & config, token, account)
980
+ }
844
981
( "wrap" , Some ( arg_matches) ) => {
845
982
let amount = value_t_or_exit ! ( arg_matches, "amount" , f64 ) ;
846
983
command_wrap ( & config, amount)
0 commit comments