Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit c7c12f9

Browse files
token-cli: support for permanent delegate (#3841)
* token-cli: support for permanent delegate * using associated account helper
1 parent 979fdc8 commit c7c12f9

File tree

1 file changed

+200
-2
lines changed

1 file changed

+200
-2
lines changed

token/cli/src/main.rs

Lines changed: 200 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use spl_token_2022::{
4242
interest_bearing_mint::InterestBearingConfig,
4343
memo_transfer::MemoTransfer,
4444
mint_close_authority::MintCloseAuthority,
45+
permanent_delegate::PermanentDelegate,
4546
transfer_fee::{TransferFeeAmount, TransferFeeConfig},
4647
BaseStateWithExtensions, ExtensionType, StateWithExtensionsOwned,
4748
},
@@ -395,6 +396,7 @@ async fn command_create_token(
395396
enable_freeze: bool,
396397
enable_close: bool,
397398
enable_non_transferable: bool,
399+
enable_permanent_delegate: bool,
398400
memo: Option<String>,
399401
rate_bps: Option<i16>,
400402
default_account_state: Option<AccountState>,
@@ -421,6 +423,12 @@ async fn command_create_token(
421423
});
422424
}
423425

426+
if enable_permanent_delegate {
427+
extensions.push(ExtensionInitializationParams::PermanentDelegate {
428+
delegate: authority,
429+
});
430+
}
431+
424432
if let Some(rate_bps) = rate_bps {
425433
extensions.push(ExtensionInitializationParams::InterestBearingConfig {
426434
rate_authority: Some(authority),
@@ -782,7 +790,16 @@ async fn command_authorize(
782790
Err(format!("Mint `{}` is not interest-bearing", account))
783791
}
784792
}
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+
}
786803
}?;
787804

788805
Ok((account, previous_authority))
@@ -2465,6 +2482,14 @@ fn app<'a, 'b>(
24652482
The mint authority can set the fee and withdraw collected fees.",
24662483
),
24672484
)
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+
)
24682493
.nonce_args(true)
24692494
.arg(memo_arg())
24702495
)
@@ -2589,7 +2614,7 @@ fn app<'a, 'b>(
25892614
.possible_values(&[
25902615
"mint", "freeze", "owner", "close",
25912616
"close-mint", "transfer-fee-config", "withheld-withdraw",
2592-
"interest-rate",
2617+
"interest-rate", "permanent-delegate",
25932618
])
25942619
.index(2)
25952620
.required(true)
@@ -3582,6 +3607,7 @@ async fn process_command<'a>(
35823607
arg_matches.is_present("enable_freeze"),
35833608
arg_matches.is_present("enable_close"),
35843609
arg_matches.is_present("enable_non_transferable"),
3610+
arg_matches.is_present("enable_permanent_delegate"),
35853611
memo,
35863612
rate_bps,
35873613
default_account_state,
@@ -4383,6 +4409,7 @@ mod tests {
43834409
false,
43844410
false,
43854411
false,
4412+
false,
43864413
None,
43874414
None,
43884415
None,
@@ -4412,6 +4439,7 @@ mod tests {
44124439
false,
44134440
false,
44144441
false,
4442+
false,
44154443
None,
44164444
Some(rate_bps),
44174445
None,
@@ -5781,6 +5809,7 @@ mod tests {
57815809
false,
57825810
true,
57835811
false,
5812+
false,
57845813
None,
57855814
None,
57865815
None,
@@ -5810,6 +5839,172 @@ mod tests {
58105839
assert!(account.is_err());
58115840
}
58125841

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+
58136008
#[tokio::test]
58146009
#[serial]
58156010
async fn required_transfer_memos() {
@@ -6087,6 +6282,7 @@ mod tests {
60876282
false,
60886283
false,
60896284
true,
6285+
false,
60906286
None,
60916287
None,
60926288
None,
@@ -6141,6 +6337,7 @@ mod tests {
61416337
true,
61426338
false,
61436339
false,
6340+
false,
61446341
None,
61456342
None,
61466343
Some(AccountState::Frozen),
@@ -6208,6 +6405,7 @@ mod tests {
62086405
false,
62096406
false,
62106407
false,
6408+
false,
62116409
None,
62126410
None,
62136411
None,

0 commit comments

Comments
 (0)