@@ -42,6 +42,7 @@ use spl_token_2022::{
42
42
interest_bearing_mint:: InterestBearingConfig ,
43
43
memo_transfer:: MemoTransfer ,
44
44
mint_close_authority:: MintCloseAuthority ,
45
+ permanent_delegate:: PermanentDelegate ,
45
46
transfer_fee:: { TransferFeeAmount , TransferFeeConfig } ,
46
47
BaseStateWithExtensions , ExtensionType , StateWithExtensionsOwned ,
47
48
} ,
@@ -395,6 +396,7 @@ async fn command_create_token(
395
396
enable_freeze : bool ,
396
397
enable_close : bool ,
397
398
enable_non_transferable : bool ,
399
+ enable_permanent_delegate : bool ,
398
400
memo : Option < String > ,
399
401
rate_bps : Option < i16 > ,
400
402
default_account_state : Option < AccountState > ,
@@ -421,6 +423,12 @@ async fn command_create_token(
421
423
} ) ;
422
424
}
423
425
426
+ if enable_permanent_delegate {
427
+ extensions. push ( ExtensionInitializationParams :: PermanentDelegate {
428
+ delegate : authority,
429
+ } ) ;
430
+ }
431
+
424
432
if let Some ( rate_bps) = rate_bps {
425
433
extensions. push ( ExtensionInitializationParams :: InterestBearingConfig {
426
434
rate_authority : Some ( authority) ,
@@ -782,7 +790,16 @@ async fn command_authorize(
782
790
Err ( format ! ( "Mint `{}` is not interest-bearing" , account) )
783
791
}
784
792
}
785
- AuthorityType :: PermanentDelegate => unimplemented ! ( ) ,
793
+ AuthorityType :: PermanentDelegate => {
794
+ if let Ok ( permanent_delegate) = mint. get_extension :: < PermanentDelegate > ( ) {
795
+ Ok ( COption :: < Pubkey > :: from ( permanent_delegate. delegate ) )
796
+ } else {
797
+ Err ( format ! (
798
+ "Mint `{}` does not support permanent delegate" ,
799
+ account
800
+ ) )
801
+ }
802
+ }
786
803
} ?;
787
804
788
805
Ok ( ( account, previous_authority) )
@@ -2465,6 +2482,14 @@ fn app<'a, 'b>(
2465
2482
The mint authority can set the fee and withdraw collected fees.",
2466
2483
) ,
2467
2484
)
2485
+ . arg (
2486
+ Arg :: with_name ( "enable_permanent_delegate" )
2487
+ . long ( "enable-permanent-delegate" )
2488
+ . takes_value ( false )
2489
+ . help (
2490
+ "Enable the mint authority to be permanent delegate for this mint"
2491
+ ) ,
2492
+ )
2468
2493
. nonce_args ( true )
2469
2494
. arg ( memo_arg ( ) )
2470
2495
)
@@ -2589,7 +2614,7 @@ fn app<'a, 'b>(
2589
2614
. possible_values ( & [
2590
2615
"mint" , "freeze" , "owner" , "close" ,
2591
2616
"close-mint" , "transfer-fee-config" , "withheld-withdraw" ,
2592
- "interest-rate" ,
2617
+ "interest-rate" , "permanent-delegate" ,
2593
2618
] )
2594
2619
. index ( 2 )
2595
2620
. required ( true )
@@ -3582,6 +3607,7 @@ async fn process_command<'a>(
3582
3607
arg_matches. is_present ( "enable_freeze" ) ,
3583
3608
arg_matches. is_present ( "enable_close" ) ,
3584
3609
arg_matches. is_present ( "enable_non_transferable" ) ,
3610
+ arg_matches. is_present ( "enable_permanent_delegate" ) ,
3585
3611
memo,
3586
3612
rate_bps,
3587
3613
default_account_state,
@@ -4383,6 +4409,7 @@ mod tests {
4383
4409
false ,
4384
4410
false ,
4385
4411
false ,
4412
+ false ,
4386
4413
None ,
4387
4414
None ,
4388
4415
None ,
@@ -4412,6 +4439,7 @@ mod tests {
4412
4439
false ,
4413
4440
false ,
4414
4441
false ,
4442
+ false ,
4415
4443
None ,
4416
4444
Some ( rate_bps) ,
4417
4445
None ,
@@ -5781,6 +5809,7 @@ mod tests {
5781
5809
false ,
5782
5810
true ,
5783
5811
false ,
5812
+ false ,
5784
5813
None ,
5785
5814
None ,
5786
5815
None ,
@@ -5810,6 +5839,172 @@ mod tests {
5810
5839
assert ! ( account. is_err( ) ) ;
5811
5840
}
5812
5841
5842
+ #[ tokio:: test]
5843
+ #[ serial]
5844
+ async fn burn_with_permanent_delegate ( ) {
5845
+ let ( test_validator, payer) = new_validator_for_test ( ) . await ;
5846
+ let config =
5847
+ test_config_with_default_signer ( & test_validator, & payer, & spl_token_2022:: id ( ) ) ;
5848
+
5849
+ let token_keypair = Keypair :: new ( ) ;
5850
+ let token = token_keypair. pubkey ( ) ;
5851
+ let bulk_signers: Vec < Arc < dyn Signer > > =
5852
+ vec ! [ Arc :: new( clone_keypair( & payer) ) , Arc :: new( token_keypair) ] ;
5853
+
5854
+ command_create_token (
5855
+ & config,
5856
+ TEST_DECIMALS ,
5857
+ token,
5858
+ payer. pubkey ( ) ,
5859
+ false ,
5860
+ false ,
5861
+ false ,
5862
+ true ,
5863
+ None ,
5864
+ None ,
5865
+ None ,
5866
+ None ,
5867
+ bulk_signers,
5868
+ )
5869
+ . await
5870
+ . unwrap ( ) ;
5871
+
5872
+ let permanent_delegate_keypair_file = NamedTempFile :: new ( ) . unwrap ( ) ;
5873
+ write_keypair_file ( & payer, & permanent_delegate_keypair_file) . unwrap ( ) ;
5874
+
5875
+ let unknown_owner = Keypair :: new ( ) ;
5876
+ let source = create_associated_account ( & config, & unknown_owner, token) . await ;
5877
+ let ui_amount = 100.0 ;
5878
+
5879
+ mint_tokens ( & config, & payer, token, ui_amount, source) . await ;
5880
+
5881
+ let ui_account = config
5882
+ . rpc_client
5883
+ . get_token_account ( & source)
5884
+ . await
5885
+ . unwrap ( )
5886
+ . unwrap ( ) ;
5887
+
5888
+ assert_eq ! ( ui_account. token_amount. amount, "100" ) ;
5889
+
5890
+ exec_test_cmd (
5891
+ & config,
5892
+ & [
5893
+ "spl-token" ,
5894
+ CommandName :: Burn . into ( ) ,
5895
+ & source. to_string ( ) ,
5896
+ "10" ,
5897
+ "--owner" ,
5898
+ permanent_delegate_keypair_file. path ( ) . to_str ( ) . unwrap ( ) ,
5899
+ ] ,
5900
+ )
5901
+ . await
5902
+ . unwrap ( ) ;
5903
+
5904
+ let ui_account = config
5905
+ . rpc_client
5906
+ . get_token_account ( & source)
5907
+ . await
5908
+ . unwrap ( )
5909
+ . unwrap ( ) ;
5910
+
5911
+ assert_eq ! ( ui_account. token_amount. amount, "90" ) ;
5912
+ }
5913
+
5914
+ #[ tokio:: test]
5915
+ #[ serial]
5916
+ async fn transfer_with_permanent_delegate ( ) {
5917
+ let ( test_validator, payer) = new_validator_for_test ( ) . await ;
5918
+ let config =
5919
+ test_config_with_default_signer ( & test_validator, & payer, & spl_token_2022:: id ( ) ) ;
5920
+
5921
+ let token_keypair = Keypair :: new ( ) ;
5922
+ let token = token_keypair. pubkey ( ) ;
5923
+ let bulk_signers: Vec < Arc < dyn Signer > > =
5924
+ vec ! [ Arc :: new( clone_keypair( & payer) ) , Arc :: new( token_keypair) ] ;
5925
+
5926
+ command_create_token (
5927
+ & config,
5928
+ TEST_DECIMALS ,
5929
+ token,
5930
+ payer. pubkey ( ) ,
5931
+ false ,
5932
+ false ,
5933
+ false ,
5934
+ true ,
5935
+ None ,
5936
+ None ,
5937
+ None ,
5938
+ None ,
5939
+ bulk_signers,
5940
+ )
5941
+ . await
5942
+ . unwrap ( ) ;
5943
+
5944
+ let unknown_owner = Keypair :: new ( ) ;
5945
+ let source = create_associated_account ( & config, & unknown_owner, token) . await ;
5946
+ let destination = create_associated_account ( & config, & payer, token) . await ;
5947
+
5948
+ let permanent_delegate_keypair_file = NamedTempFile :: new ( ) . unwrap ( ) ;
5949
+ write_keypair_file ( & payer, & permanent_delegate_keypair_file) . unwrap ( ) ;
5950
+
5951
+ let ui_amount = 100.0 ;
5952
+ mint_tokens ( & config, & payer, token, ui_amount, source) . await ;
5953
+
5954
+ let ui_account = config
5955
+ . rpc_client
5956
+ . get_token_account ( & source)
5957
+ . await
5958
+ . unwrap ( )
5959
+ . unwrap ( ) ;
5960
+
5961
+ assert_eq ! ( ui_account. token_amount. amount, "100" ) ;
5962
+
5963
+ let ui_account = config
5964
+ . rpc_client
5965
+ . get_token_account ( & destination)
5966
+ . await
5967
+ . unwrap ( )
5968
+ . unwrap ( ) ;
5969
+
5970
+ assert_eq ! ( ui_account. token_amount. amount, "0" ) ;
5971
+
5972
+ exec_test_cmd (
5973
+ & config,
5974
+ & [
5975
+ "spl-token" ,
5976
+ CommandName :: Transfer . into ( ) ,
5977
+ & token. to_string ( ) ,
5978
+ "50" ,
5979
+ & destination. to_string ( ) ,
5980
+ "--from" ,
5981
+ & source. to_string ( ) ,
5982
+ "--owner" ,
5983
+ permanent_delegate_keypair_file. path ( ) . to_str ( ) . unwrap ( ) ,
5984
+ ] ,
5985
+ )
5986
+ . await
5987
+ . unwrap ( ) ;
5988
+
5989
+ let ui_account = config
5990
+ . rpc_client
5991
+ . get_token_account ( & destination)
5992
+ . await
5993
+ . unwrap ( )
5994
+ . unwrap ( ) ;
5995
+
5996
+ assert_eq ! ( ui_account. token_amount. amount, "50" ) ;
5997
+
5998
+ let ui_account = config
5999
+ . rpc_client
6000
+ . get_token_account ( & source)
6001
+ . await
6002
+ . unwrap ( )
6003
+ . unwrap ( ) ;
6004
+
6005
+ assert_eq ! ( ui_account. token_amount. amount, "50" ) ;
6006
+ }
6007
+
5813
6008
#[ tokio:: test]
5814
6009
#[ serial]
5815
6010
async fn required_transfer_memos ( ) {
@@ -6087,6 +6282,7 @@ mod tests {
6087
6282
false ,
6088
6283
false ,
6089
6284
true ,
6285
+ false ,
6090
6286
None ,
6091
6287
None ,
6092
6288
None ,
@@ -6141,6 +6337,7 @@ mod tests {
6141
6337
true ,
6142
6338
false ,
6143
6339
false ,
6340
+ false ,
6144
6341
None ,
6145
6342
None ,
6146
6343
Some ( AccountState :: Frozen ) ,
@@ -6208,6 +6405,7 @@ mod tests {
6208
6405
false ,
6209
6406
false ,
6210
6407
false ,
6408
+ false ,
6211
6409
None ,
6212
6410
None ,
6213
6411
None ,
0 commit comments