46
46
confidential_transfer_fee:: ConfidentialTransferFeeConfig ,
47
47
cpi_guard:: CpiGuard ,
48
48
default_account_state:: DefaultAccountState ,
49
+ group_member_pointer:: GroupMemberPointer ,
49
50
group_pointer:: GroupPointer ,
50
51
interest_bearing_mint:: InterestBearingConfig ,
51
52
memo_transfer:: MemoTransfer ,
@@ -176,6 +177,14 @@ fn native_token_client_from_config(
176
177
}
177
178
}
178
179
180
+ #[ derive( strum_macros:: Display , Debug ) ]
181
+ #[ strum( serialize_all = "kebab-case" ) ]
182
+ enum Pointer {
183
+ Metadata ,
184
+ Group ,
185
+ GroupMember ,
186
+ }
187
+
179
188
#[ allow( clippy:: too_many_arguments) ]
180
189
async fn command_create_token (
181
190
config : & Config < ' _ > ,
@@ -189,13 +198,15 @@ async fn command_create_token(
189
198
memo : Option < String > ,
190
199
metadata_address : Option < Pubkey > ,
191
200
group_address : Option < Pubkey > ,
201
+ member_address : Option < Pubkey > ,
192
202
rate_bps : Option < i16 > ,
193
203
default_account_state : Option < AccountState > ,
194
204
transfer_fee : Option < ( u16 , u64 ) > ,
195
205
confidential_transfer_auto_approve : Option < bool > ,
196
206
transfer_hook_program_id : Option < Pubkey > ,
197
207
enable_metadata : bool ,
198
208
enable_group : bool ,
209
+ enable_member : bool ,
199
210
bulk_signers : Vec < Arc < dyn Signer > > ,
200
211
) -> CommandResult {
201
212
println_display (
@@ -296,6 +307,18 @@ async fn command_create_token(
296
307
} ) ;
297
308
}
298
309
310
+ if member_address. is_some ( ) || enable_member {
311
+ let member_address = if enable_member {
312
+ Some ( token_pubkey)
313
+ } else {
314
+ member_address
315
+ } ;
316
+ extensions. push ( ExtensionInitializationParams :: GroupMemberPointer {
317
+ authority : Some ( authority) ,
318
+ member_address,
319
+ } ) ;
320
+ }
321
+
299
322
let res = token
300
323
. create_mint (
301
324
& authority,
@@ -327,6 +350,15 @@ async fn command_create_token(
327
350
) ;
328
351
}
329
352
353
+ if enable_member {
354
+ println_display (
355
+ config,
356
+ format ! (
357
+ "To initialize group member configurations inside the mint, please run `spl-token initialize-member {token_pubkey}`, and sign with the mint authority and the group's update authority." ,
358
+ ) ,
359
+ ) ;
360
+ }
361
+
330
362
Ok ( match tx_return {
331
363
TransactionReturnData :: CliSignature ( cli_signature) => format_output (
332
364
CliCreateToken {
@@ -871,6 +903,16 @@ async fn command_authorize(
871
903
) )
872
904
}
873
905
}
906
+ CliAuthorityType :: GroupMemberPointer => {
907
+ if let Ok ( extension) = mint. get_extension :: < GroupMemberPointer > ( ) {
908
+ Ok ( Option :: < Pubkey > :: from ( extension. authority ) )
909
+ } else {
910
+ Err ( format ! (
911
+ "Mint `{}` does not support a group member pointer" ,
912
+ account
913
+ ) )
914
+ }
915
+ }
874
916
} ?;
875
917
876
918
Ok ( ( account, previous_authority) )
@@ -910,7 +952,8 @@ async fn command_authorize(
910
952
| CliAuthorityType :: ConfidentialTransferFee
911
953
| CliAuthorityType :: MetadataPointer
912
954
| CliAuthorityType :: Metadata
913
- | CliAuthorityType :: GroupPointer => Err ( format ! (
955
+ | CliAuthorityType :: GroupPointer
956
+ | CliAuthorityType :: GroupMemberPointer => Err ( format ! (
914
957
"Authority type `{auth_str}` not supported for SPL Token accounts" ,
915
958
) ) ,
916
959
CliAuthorityType :: Owner => {
@@ -2491,48 +2534,39 @@ async fn command_cpi_guard(
2491
2534
} )
2492
2535
}
2493
2536
2494
- async fn command_update_metadata_pointer_address (
2537
+ async fn command_update_pointer_address (
2495
2538
config : & Config < ' _ > ,
2496
2539
token_pubkey : Pubkey ,
2497
2540
authority : Pubkey ,
2498
- new_metadata_address : Option < Pubkey > ,
2541
+ new_address : Option < Pubkey > ,
2499
2542
bulk_signers : BulkSigners ,
2543
+ pointer : Pointer ,
2500
2544
) -> CommandResult {
2501
2545
if config. sign_only {
2502
- panic ! ( "Config can not be sign-only for updating metadata pointer address." ) ;
2546
+ panic ! (
2547
+ "Config can not be sign-only for updating {} pointer address." ,
2548
+ pointer
2549
+ ) ;
2503
2550
}
2504
2551
2505
2552
let token = token_client_from_config ( config, & token_pubkey, None ) ?;
2506
- let res = token
2507
- . update_metadata_address ( & authority, new_metadata_address, & bulk_signers)
2508
- . await ?;
2509
-
2510
- let tx_return = finish_tx ( config, & res, false ) . await ?;
2511
- Ok ( match tx_return {
2512
- TransactionReturnData :: CliSignature ( signature) => {
2513
- config. output_format . formatted_string ( & signature)
2553
+ let res = match pointer {
2554
+ Pointer :: Metadata => {
2555
+ token
2556
+ . update_metadata_address ( & authority, new_address, & bulk_signers)
2557
+ . await
2514
2558
}
2515
- TransactionReturnData :: CliSignOnlyData ( sign_only_data) => {
2516
- config. output_format . formatted_string ( & sign_only_data)
2559
+ Pointer :: Group => {
2560
+ token
2561
+ . update_group_address ( & authority, new_address, & bulk_signers)
2562
+ . await
2517
2563
}
2518
- } )
2519
- }
2520
-
2521
- async fn command_update_group_pointer_address (
2522
- config : & Config < ' _ > ,
2523
- token_pubkey : Pubkey ,
2524
- authority : Pubkey ,
2525
- new_group_address : Option < Pubkey > ,
2526
- bulk_signers : BulkSigners ,
2527
- ) -> CommandResult {
2528
- if config. sign_only {
2529
- panic ! ( "Config can not be sign-only for updating group pointer address." ) ;
2530
- }
2531
-
2532
- let token = token_client_from_config ( config, & token_pubkey, None ) ?;
2533
- let res = token
2534
- . update_group_address ( & authority, new_group_address, & bulk_signers)
2535
- . await ?;
2564
+ Pointer :: GroupMember => {
2565
+ token
2566
+ . update_group_member_address ( & authority, new_address, & bulk_signers)
2567
+ . await
2568
+ }
2569
+ } ?;
2536
2570
2537
2571
let tx_return = finish_tx ( config, & res, false ) . await ?;
2538
2572
Ok ( match tx_return {
@@ -3253,6 +3287,7 @@ pub async fn process_command<'a>(
3253
3287
let rate_bps = value_t ! ( arg_matches, "interest_rate" , i16 ) . ok ( ) ;
3254
3288
let metadata_address = value_t ! ( arg_matches, "metadata_address" , Pubkey ) . ok ( ) ;
3255
3289
let group_address = value_t ! ( arg_matches, "group_address" , Pubkey ) . ok ( ) ;
3290
+ let member_address = value_t ! ( arg_matches, "member_address" , Pubkey ) . ok ( ) ;
3256
3291
3257
3292
let transfer_fee = arg_matches. values_of ( "transfer_fee" ) . map ( |mut v| {
3258
3293
(
@@ -3298,13 +3333,15 @@ pub async fn process_command<'a>(
3298
3333
memo,
3299
3334
metadata_address,
3300
3335
group_address,
3336
+ member_address,
3301
3337
rate_bps,
3302
3338
default_account_state,
3303
3339
transfer_fee,
3304
3340
confidential_transfer_auto_approve,
3305
3341
transfer_hook_program_id,
3306
3342
arg_matches. is_present ( "enable_metadata" ) ,
3307
3343
arg_matches. is_present ( "enable_group" ) ,
3344
+ arg_matches. is_present ( "enable_member" ) ,
3308
3345
bulk_signers,
3309
3346
)
3310
3347
. await
@@ -3961,12 +3998,13 @@ pub async fn process_command<'a>(
3961
3998
}
3962
3999
let metadata_address = value_t ! ( arg_matches, "metadata_address" , Pubkey ) . ok ( ) ;
3963
4000
3964
- command_update_metadata_pointer_address (
4001
+ command_update_pointer_address (
3965
4002
config,
3966
4003
token,
3967
4004
authority,
3968
4005
metadata_address,
3969
4006
bulk_signers,
4007
+ Pointer :: Metadata ,
3970
4008
)
3971
4009
. await
3972
4010
}
@@ -3983,12 +4021,36 @@ pub async fn process_command<'a>(
3983
4021
}
3984
4022
let group_address = value_t ! ( arg_matches, "group_address" , Pubkey ) . ok ( ) ;
3985
4023
3986
- command_update_group_pointer_address (
4024
+ command_update_pointer_address (
3987
4025
config,
3988
4026
token,
3989
4027
authority,
3990
4028
group_address,
3991
4029
bulk_signers,
4030
+ Pointer :: Group ,
4031
+ )
4032
+ . await
4033
+ }
4034
+ ( CommandName :: UpdateMemberAddress , arg_matches) => {
4035
+ // Since account is required argument it will always be present
4036
+ let token = pubkey_of_signer ( arg_matches, "token" , & mut wallet_manager)
4037
+ . unwrap ( )
4038
+ . unwrap ( ) ;
4039
+
4040
+ let ( authority_signer, authority) =
4041
+ config. signer_or_default ( arg_matches, "authority" , & mut wallet_manager) ;
4042
+ if config. multisigner_pubkeys . is_empty ( ) {
4043
+ push_signer_with_dedup ( authority_signer, & mut bulk_signers) ;
4044
+ }
4045
+ let member_address = value_t ! ( arg_matches, "member_address" , Pubkey ) . ok ( ) ;
4046
+
4047
+ command_update_pointer_address (
4048
+ config,
4049
+ token,
4050
+ authority,
4051
+ member_address,
4052
+ bulk_signers,
4053
+ Pointer :: GroupMember ,
3992
4054
)
3993
4055
. await
3994
4056
}
0 commit comments